| PostgreSQL 7.4 文檔 | ||||
|---|---|---|---|---|
| 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 命令時才能正確工作。