支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不再支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

32.10. 與 COPY 指令相關的函數 #

PostgreSQL 中的 COPY 指令具有從 libpq 使用的網路連線讀取或寫入的選項。本節中描述的函數允許應用程式透過提供或使用複製的資料來利用此功能。

整個過程是應用程式首先透過 PQexec 或其中一個等效函數發出 SQL COPY 指令。對此的回應(如果指令中沒有錯誤)將是一個 PGresult 物件,其狀態碼為 PGRES_COPY_OUTPGRES_COPY_IN(取決於指定的複製方向)。然後,應用程式應使用本節的函數來接收或傳輸資料列。資料傳輸完成後,將傳回另一個 PGresult 物件以指示傳輸成功或失敗。其狀態將為 PGRES_COMMAND_OK 表示成功,或 PGRES_FATAL_ERROR 表示遇到某些問題。此時,可以透過 PQexec 發出進一步的 SQL 指令。(在 COPY 操作正在進行時,無法使用相同的連線執行其他 SQL 指令。)

如果在可能包含其他指令的字串中透過 PQexec 發出 COPY 指令,則應用程式必須在完成 COPY 序列後,繼續透過 PQgetResult 提取結果。只有當 PQgetResult 傳回 NULL 時,才能確定 PQexec 指令字串已完成,並且可以安全地發出更多指令。

只有在從 PQexecPQgetResult 獲得 PGRES_COPY_OUTPGRES_COPY_IN 的結果狀態後,才應執行本節的函數。

帶有這些狀態值之一的 PGresult 物件攜帶有關正在啟動的 COPY 操作的一些額外資料。可以使用也用於查詢結果的函數來取得此額外資料

PQnfields #

傳回要複製的欄(欄位)數量。

PQbinaryTuples #

0 表示整體複製格式為文字(行由換行符分隔,欄由分隔符分隔等)。1 表示整體複製格式為二進位。有關更多資訊,請參閱 COPY

PQfformat #

傳回與複製操作的每一欄相關聯的格式代碼(0 代表文字,1 代表二進位)。當整體複製格式為文字時,每欄的格式代碼將始終為零,但二進位格式可以同時支援文字和二進位欄。(但是,截至目前 COPY 的實作,只有二進位欄出現在二進位複製中;因此,目前每欄的格式始終與整體格式匹配。)

32.10.1. 用於傳送 COPY 資料的函數 #

這些函數用於在 COPY FROM STDIN 期間傳送資料。如果在連線未處於 COPY_IN 狀態時呼叫,它們將會失敗。

PQputCopyData #

COPY_IN 狀態期間將資料傳送到伺服器。

int PQputCopyData(PGconn *conn,
                  const char *buffer,
                  int nbytes);

將指定 buffer 中的 COPY 資料,傳送到伺服器,資料長度為 nbytes。如果資料已排入佇列,則結果為 1;如果由於緩衝區已滿而未排入佇列(這只會在非阻塞模式下發生),則結果為零;如果發生錯誤,則結果為 -1。(如果返回值為 -1,請使用 PQerrorMessage 檢索詳細資訊。如果值為零,請等待可寫入狀態,然後重試。)

應用程式可以將 COPY 資料流分成任何方便大小的緩衝區載入量。在傳送時,緩衝區載入量邊界沒有語義意義。資料流的內容必須符合 COPY 命令所預期的資料格式;有關詳細資訊,請參閱 COPY

PQputCopyEnd #

COPY_IN 狀態期間,向伺服器傳送資料結束指示。

int PQputCopyEnd(PGconn *conn,
                 const char *errormsg);

如果 errormsgNULL,則成功結束 COPY_IN 操作。如果 errormsg 不為 NULL,則強制 COPY 失敗,並將 errormsg 指向的字串用作錯誤訊息。(但是,不應假設伺服器會傳回完全相同的錯誤訊息,因為伺服器可能已經因為自身原因而導致 COPY 失敗。)

如果已傳送終止訊息,則結果為 1;或者在非阻塞模式下,這可能只表示終止訊息已成功排入佇列。(在非阻塞模式下,為了確定資料已傳送,您應接下來等待可寫入狀態並呼叫 PQflush,重複直到它傳回零。)零表示該函數由於緩衝區已滿而無法將終止訊息排入佇列;這只會在非阻塞模式下發生。(在這種情況下,請等待可寫入狀態並再次嘗試 PQputCopyEnd 呼叫。)如果發生嚴重錯誤,則傳回 -1;您可以使用 PQerrorMessage 檢索詳細資訊。

成功呼叫 PQputCopyEnd 後,呼叫 PQgetResult 以取得 COPY 命令的最終結果狀態。可以以通常的方式等待此結果可用。然後返回正常操作。

32.10.2. 用於接收 COPY 資料的函數 #

這些函數用於在 COPY TO STDOUT 期間接收資料。如果在連線不在 COPY_OUT 狀態時呼叫它們,它們將會失敗。

PQgetCopyData #

COPY_OUT 狀態期間,從伺服器接收資料。

int PQgetCopyData(PGconn *conn,
                  char **buffer,
                  int async);

嘗試在 COPY 期間從伺服器取得另一個資料列。資料總是每次傳回一個資料列;如果只有部分列可用,則不會傳回。成功傳回資料列涉及分配一塊記憶體來保存資料。buffer 參數必須是非 NULL*buffer 會被設定為指向已分配的記憶體,或者在沒有傳回緩衝區的情況下,設定為 NULL。不再需要時,應該使用 PQfreemem 釋放非 NULL 的結果緩衝區。

當成功傳回一列時,傳回值是該列中的資料位元組數(這將總是大於零)。傳回的字串總是帶有空字元結尾,雖然這可能只對文字 COPY 有用。結果為零表示 COPY 仍在進行中,但尚未有可用列(只有當 async 為 true 時才可能)。結果為 -1 表示 COPY 已完成。結果為 -2 表示發生錯誤(有關原因,請參閱 PQerrorMessage)。

async 為 true(非零)時,PQgetCopyData 將不會阻塞等待輸入;如果 COPY 仍在進行中但沒有可用的完整列,它將傳回零。(在這種情況下,等待可讀取狀態,然後在再次呼叫 PQgetCopyData 之前呼叫 PQconsumeInput。)當 async 為 false(零)時,PQgetCopyData 將會阻塞,直到資料可用或操作完成。

PQgetCopyData 傳回 -1 後,呼叫 PQgetResult 以取得 COPY 命令的最終結果狀態。可以以通常的方式等待此結果可用。然後返回正常操作。

32.10.3. 已過時的 COPY 函數 #

這些函數代表處理 COPY 的較舊方法。雖然它們仍然有效,但由於錯誤處理不佳、檢測資料結束的不方便方法以及缺乏對二進位或非阻塞傳輸的支援,因此它們已被棄用。

PQgetline #

將伺服器傳輸的以換行符號結尾的字元行讀取到大小為 length 的緩衝區字串中。

int PQgetline(PGconn *conn,
              char *buffer,
              int length);

此函數最多複製 length-1 個字元到緩衝區中,並將結尾的換行符號轉換為零位元組。PQgetline 在輸入結束時傳回 EOF,如果已讀取整行,則傳回 0,如果緩衝區已滿但尚未讀取結尾的換行符號,則傳回 1。

請注意,應用程式必須檢查新行是否由兩個字元 \. 組成,這表示伺服器已完成傳送 COPY 命令的結果。如果應用程式可能接收到超過 length-1 個字元的行,則需要小心以確保它正確識別 \. 行(並且不會,例如,將長資料行的結尾誤認為終止符行)。

PQgetlineAsync #

在不阻塞的情況下,讀取一行 COPY 資料(由伺服器傳輸)到緩衝區中。

int PQgetlineAsync(PGconn *conn,
                   char *buffer,
                   int bufsize);

此函數與 PQgetline 類似,但它可被必須非同步讀取 COPY 資料的應用程式使用,也就是說,不能阻塞。在發出 COPY 指令和收到 PGRES_COPY_OUT 回應後,應用程式應該呼叫 PQconsumeInputPQgetlineAsync,直到偵測到資料結束訊號。

PQgetline 不同,此函數負責偵測資料結束。

在每次呼叫時,如果 libpq 的輸入緩衝區中存在完整的資料列,PQgetlineAsync 將會回傳資料。否則,除非其餘資料列到達,否則不會回傳資料。如果已識別出複製資料結束標記,該函數會回傳 -1;如果沒有可用的資料,則回傳 0;或者回傳一個正數,表示回傳的資料位元組數。如果回傳 -1,則呼叫者必須接著呼叫 PQendcopy,然後恢復正常處理。

回傳的資料不會超出資料列的邊界。如果可能,將一次回傳整列資料。但如果呼叫者提供的緩衝區太小,無法容納伺服器傳送的資料列,則會回傳部分資料列。對於文字資料,可以透過測試最後回傳的位元組是否為 \n 來偵測到這一點。(在二進制 COPY 中,需要實際解析 COPY 資料格式才能做出等效的判斷。)回傳的字串不是以 null 字元結尾。(如果您想新增一個終止 null 字元,請務必傳遞一個比實際可用空間小一的 bufsize。)

PQputline #

將一個以 null 字元結尾的字串傳送到伺服器。如果成功則回傳 0,如果無法傳送字串則回傳 EOF

int PQputline(PGconn *conn,
              const char *string);

由一系列對 PQputline 的呼叫所傳送的 COPY 資料流具有與 PQgetlineAsync 回傳的資料流相同的格式,只是應用程式不必每次 PQputline 呼叫都傳送剛好一個資料列;每次呼叫傳送部分行或多行是可以的。

注意

PostgreSQL 協定 3.0 之前,應用程式必須明確地傳送兩個字元 \. 作為最後一行,以向伺服器指示它已完成傳送 COPY 資料。雖然這仍然有效,但已被棄用,並且可以預期 \. 的特殊意義將在未來的版本中移除。在傳送實際資料後呼叫 PQendcopy 就足夠了。

PQputnbytes #

將一個非 null 字元結尾的字串傳送到伺服器。如果成功則回傳 0,如果無法傳送字串則回傳 EOF

int PQputnbytes(PGconn *conn,
                const char *buffer,
                int nbytes);

這與 PQputline 完全一樣,只是資料緩衝區不必以 null 字元結尾,因為要傳送的位元組數是直接指定的。在傳送二進制資料時,請使用此過程。

PQendcopy #

與伺服器同步。

int PQendcopy(PGconn *conn);

此函數會等待,直到伺服器完成複製。它應該在最後一個字串使用 PQputline 傳送到伺服器後,或在最後一個字串使用 PQgetline 從伺服器收到後發出。必須發出它,否則伺服器將與客戶端失去同步(out of sync)。從此函數回傳後,伺服器已準備好接收下一個 SQL 指令。成功完成時回傳值為 0,否則為非零值。(如果回傳值為非零值,請使用 PQerrorMessage 來檢索詳細資訊。)

使用 PQgetResult 時,應用程式應透過重複執行 PQgetline,接著在看到終止符號行後執行 PQendcopy 來回應 PGRES_COPY_OUT 結果。然後,它應該回傳到 PQgetResult 迴圈,直到 PQgetResult 回傳一個 null 指標。同樣地,PGRES_COPY_IN 結果會透過一系列的 PQputline 呼叫處理,接著是 PQendcopy,然後回傳到 PQgetResult 迴圈。此安排將確保嵌入在一系列中的 COPY 指令SQL指令將正確執行。

較舊的應用程式可能會透過 PQexec 提交一個 COPY,並假設在 PQendcopy 之後交易就完成了。只有當 COPY 是指令字串中的唯一SQL指令時,這才會正確運作。

提交更正

如果您在文件中發現任何不正確、與您特定功能的使用經驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。