| PostgreSQL 8.0.0 中文文件(轉譯自 PostgreSQL 中國 製作的簡體中文版本) | ||||
|---|---|---|---|---|
| Prev | Fast Backward | Chapter 27. libpq - C 庫 | Fast Forward | Next |
PostgreSQL 裡的 COPY 命令裡有用於 libpq 裡從網絡連接讀出或者寫入的選項。 本節描述的函數允許應用透過提供或者消耗拷貝資料,充分利用這個功能。
整個過程是應用首先透過 PQexec 或者一個等效的函數發出 SQL COPY 命令。 對這個命令的相應(如果命令無誤)將是一個帶著狀態碼 PGRES_COPY_OUT 或者 PGRES_COPY_IN 的 PGresult(具體根據聲明的拷貝方向)。 應用然後就應該使用本節的函數接受或者發送資料行。在資料傳輸結束之後,返回另外一個 PGresult 對像以資料表明傳輸的成功或者失敗。它的狀態將是 PGRES_COMMAND_OK 資料表示成功或者 如果發生了一些問題,是 PGRES_FATAL_ERROR。 這個時候開始我們可以透過 PQexec 發出更多 SQL 命令。 (在 COPY 操作在處理的過程中,我們不可能用同一個連接執行其它 SQL 命令。
如果一個 COPY 是透過 PQexec 在一個可以包含額外命令的字串裡發出的, 那麼應用在完成 COPY 序列之後必須繼續用 PQgetResult 抓取結果。 只有在 PQgetResult 返回 NULL 的時候,我們才能確信 PQexec 的命令字串已經處理完畢,並且已經可以安全地發出更多命令。
本節地這些函數應該只在從 PQexec 或 PQgetResult 獲得了 PGRES_COPY_OUT 或 PGRES_COPY_IN 結果狀態的情況下執行。
一個承載了這些狀態值之一地 PGresult 對像運載了某些有關正在開始地 COPY 操作的額外訊息。這些額外的資料可以用那些同時也處理查詢 結果的函數獲取。
返回要拷貝的字串(資料域)個數。
0 資料表示全部拷貝格式都是文本的(行之間用換行分隔,字串用分隔符分隔,等等)。 1 資料表示全部拷貝格式都是二進制。參閱 COPY 獲取更多訊息。
返回和拷貝操作的每個字串相關的格式代碼(0 是文本,1 是二進制)。 如果全部拷貝格式是文本,那麼每字串的格式碼將總是零,但是(總體)二進制格式可以支援文本和二進制字串並存。 (不過,就目前的 COPY 實現,在二進制拷貝裡只出現二進制字串; 所以目前每字串的格式總是匹配縱起格式。)
注意: 這些額外的資料值只能在使用 3.0 版本的協議的時候獲得。在使用 2.0 版本的協議時,所有這些函數都返回 0。
這些函數用於在 COPY FROM STDIN 過程中發送資料。 如果在連接不是處於 COPY_IN 狀態下,它們會失敗。
在 COPY_IN 狀態期間向伺服器發送資料。
int PQputCopyData(PGconn *conn,
const char *buffer,
int nbytes);傳輸指定的 buffer 裡的,長度為 nbytes 的 COPY 資料到伺服器。 如果資料發送成功,結果是 1,如果因為發送企圖會阻塞(這種情況只有在連接是非阻塞模式時才有可能)而沒有成功, 那麼是零,或者是在發生錯誤的時候是 -1。(如果返回 -1,那麼使用 PQerrorMessage 檢索細節。 如果值是零,那麼等待寫準備好然後重試。)
應用可以把 COPY 資料流分隔成任意合適的大小放到緩衝區裡。 在發送的時候,緩衝區的邊界沒有什麼特殊的語意。資料流的內容必須匹配 COPY 命令預期的資料格式; 參閱 COPY 獲取細節。
在 COPY_IN 狀態裡向伺服器發送資料完畢的指示。
int PQputCopyEnd(PGconn *conn,
const char *errormsg);如果 errormsg 是 NULL,則成功結束 COPY_IN 操作。 如果 errormsg 不是 NULL 則 COPY 操作被強制失敗, errormsg 指向的字串是錯誤訊息。(我們不能認為同樣的訊息可能會從伺服器傳回, 因為伺服器可能已經因為自己的原因讓 COPY 失敗。還要注意的是在使用 3.0 版本之前的協議連接時, 強制失敗的選項是不能用的。)
如果終止資料發送,則結果為 1,如果發送企圖會阻塞(只有在連接是在非阻塞模式的情況下才可能出現這個情況), 則為零,如果發生錯誤則返回 -1。(如果返回值是 -1,用 PQerrorMessage 檢索細節。 如果值是零,那麼等待寫準備好然後重新嘗試。)
在成功調用 PQputCopyEnd 之後,調用 PQgetResult 獲取 COPY 命令的最終結果狀態。 我們可以用平常的方法來等待這個結果可用。然後返回到正常的操作。
這些函數用於在 COPY TO STDOUT 的過程中檢索資料。 如果連接不在 COPY_OUT 狀態,那麼他們將會失敗。
在 COPY_OUT 狀態下從伺服器接收資料。
int PQgetCopyData(PGconn *conn,
char **buffer,
int async);在一個 COPY 的過程中試圖獲取另外一行資料。 資料總是每次返回一個資料行;如果只有一行的部分可用,那麼它不會被返回。 成功返回一個資料行包括分配一個內存塊來保存這些資料。 buffer 參數必須是非 NULL。 *buffer 設置為指向分配出來的內存的指針,或者是如果沒有返回緩衝區,那麼為 NULL。 一個非NULL的結果緩衝區在不再需要的時候必須用 PQfreemem 釋放。
在成功返回一行之後,那麼返回的值就是該資料行裡資料的字元數(這個將總是大於零)。 返回的字串總是空結尾的,雖然可能只是對文本的 COPY 有用。 一個零的結果資料表示該 COPY 仍然在處理中,但是還沒有可以用的行(這個只有在 async 為真的時候才可能)。 一個結果為 -1 的值資料表示 COPY 已經結束。結果為 -2 資料表示發生了錯誤(參考 PQerrorMessage 獲取原因)。
在 async 為真的時候(非零),PQgetCopyData 將不會阻塞住等待輸入; 如果該 COPY 仍在處理過程中並且沒有可用的完整行,那麼它將返回零。 (在這種情況下它在重新嘗試之前等待讀準備好;它並不關心您是否調用了 PQconsumeInput。) 在 async 是假(零)的時候,PQgetCopyData 將阻塞住,知道有可用的資料或者操作完成。
在 PQgetCopyData 返回 -1 之後,調用 PQgetResult 獲取 COPY 命令的最後結果狀態。 我們可以用通常的方法等待這個結果可用。然後返回到正常操作。
下面的這些函數代資料表了以前的處理 COPY 的方法。 儘管他們還能用,但是現在已經廢棄了,因為他們的錯誤處理實在是太糟糕了, 並且檢測資料結束的方法也很不方便,並且缺少對二進制何非阻塞傳輸的支援。
讀取一個以新行符結尾的字元行中指定字元數的字元(由伺服器伺服器傳輸)到一個長度為 length 的字元串緩衝區。
int PQgetline(PGconn *conn, char *buffer, int length);
這個函數拷貝最多length-1 個字元到緩衝區裡,然後把終止的新行符轉換成一個字元零。 PQgetline 在輸入結束時返回 EOF, 如果整行都被讀取了返回 0,如果緩衝區填滿了而還沒有遇到結束的新行符則返回 1。
注意,應用程序必須檢查新行是否包含兩個字元 \., 這資料表明伺服器伺服器已經完成了 COPY 命令的結果的發送。 如果應用可能收到超過length-1 字元長的字元,我們就應該確保正確識別\.行 (例如,不要把一個長的行的結束當作一個終止行)。
不做阻塞地讀取一行 COPY 資料(由伺服器伺服器傳輸)到一個緩衝區中。
int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
這個函數類似於 PQgetline,但是可以用於那些必須異步地讀取 COPY資料的應用,也就是不阻塞的應用。在使用了COPY命令和獲取了 PGRES_COPY_OUT響應之後,應用應該調用 PQconsumeInput 和 PQgetlineAsync 直到收到資料結束的信號。
不像PQgetline,這個函數負責檢測資料結束。
在每次調用時,如果libpq 的輸入緩衝區內有可用的一個完整的換行符結尾的資料行, PQgetlineAsync 都將返回資料。 否則,在其他資料到達之前不會返回資料。 如果見到了拷貝資料結束的標誌,此函數返回 -1,如果沒有可用資料返回 0, 或者是給出一個正數資料表明返回的資料的字元數。如果返回 -1,調用者下一步必須調用 PQendcopy,然後回到正常處理。
返回的資料將不超過一行的範圍。 如果可能,每次將返回一個完整行。但如果調用者提供的緩衝區太小, 無法容下伺服器發出的整行,那麼將返回部分行。這個可以透過測試返回的最後一個字元是否 \n 來確認。 在二進制 COPY 中,我們需要對 COPY 資料格式進行實際的分析,以便做相同的判斷。) 返回的字元串不是空結尾的。 (如果您想得到一個空結尾的字串,確保您傳遞了一個 比實際可用空間少一字元的bufsize。)
向伺服器伺服器發送一個空結尾的字元串。成功時返回 0,如果不能發送字元串返回 EOF。
int PQputline(PGconn *conn, const char *string);
一系列 PQputline 調用發送的 COPY 資料流和 PQgetlineAsync 返回的資料有著一樣的格式, 只是應用不需要明確地在每次 PQputline 調用中發送一個資料行;我們每次調用裡發送多行或者部分行都是可以的。
注意: 在 PostgreSQL 3.0 版本的協議之前,應用必須明確地發送兩個字元 \. 給伺服器, 告訴伺服器它已經完成 COPY 資料的發送。雖然這麼做仍然有效,但是已經廢棄了, \. 的特殊含義可能在將來的版本中刪除。在發送完實際資料之後,調用 PQendcopy 就足夠了。
向伺服器伺服器發送一個非空結尾的字元串。成功時返回 0,如果不能發送字元串返回 EOF。
int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
此函數類似 PQputline,除了資料緩衝區不需要是空結尾的之外,因為要發送的字元數是直接聲明的。 在發送二進制資料的時候使用這個過程。
與伺服器同步。
int PQendcopy(PGconn *conn);
這個函數等到伺服器完成拷貝(才返回?)。 您可以在用 PQputline 向伺服器發送完最後一個字元串後或者用 PGgetline從伺服器獲取最後一行字元串後調用它。 我們必須調用這個函數,否則伺服器可能會和前端"同步丟失"。在這個函數返回後, 伺服器就已經準備好接收下一個 SQL 命令了。成功時返回0,否則返回非零值。 (如果返回值為非 0,用 PQerrorMessage 檢索細節。)
在使用 PQgetResult時,應用應該對 PGRES_COPY_OUT 的結果做出反應:重複調用 PQgetline,並且在收到結束行時調用 PQendcopy。 然後應該返回到 PQgetResult 循環直到 PQgetResult 返回 NULL。 類似地, PGRES_COPY_IN 結果是用一系列 PQputline 調用最後跟著 PQendcopy,然後返回到 PQgetResult 循環。 這樣的排列將保證嵌入到一系列 SQL 命令裡的 COPY 命令將被正確執行。
舊的應用大多透過 PQexec 提交一個 COPY 命令並且假設在 PQendcopy 後交易完成。 這樣只有在 COPY 是命令字串裡的唯一的 SQL 命令時才能正確工作。