2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 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 表示資料已排隊,0 表示由於緩衝區已滿未排隊(這僅發生在非阻塞模式下),或 -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 的結果緩衝區。

當成功返回一行時,返回值是該行中資料的位元組數(始終大於零)。返回的字串始終以 null 結尾,儘管這可能僅對文字 COPY 有用。返回 0 表示 COPY 仍在進行中,但尚未準備好行(僅當 async 為 true 時才可能)。返回 -1 表示 COPY 已完成。返回 -2 表示發生錯誤(請參閱 PQerrorMessage 獲取原因)。

async 為 true(非零)時,PQgetCopyData 不會阻塞等待輸入;如果 COPY 仍在進行中但尚未準備好完整行,它將返回零。(在這種情況下,等待資料可讀,然後呼叫 PQconsumeInput,然後再呼叫 PQgetCopyData。)當 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 資料。雖然這仍然有效,但已棄用,並且 \. 的特殊含義預計將在未來版本中被移除。(它在 CSV 模式下可能已出現問題。)在傳送實際資料後呼叫 PQendcopy 就足夠了。

PQputnbytes #

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

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

這與 PQputline 完全相同,不同之處在於資料緩衝區不必是 null 結尾的,因為要傳送的位元組數是直接指定的。傳送二進位制資料時使用此過程。

PQendcopy #

與伺服器同步。

int PQendcopy(PGconn *conn);

此函式等待直到伺服器完成複製。當使用 PQputline 向伺服器傳送最後一條字串,或者使用 PQgetline 從伺服器接收最後一條字串時,都應發出此函式。必須發出此函式,否則伺服器將與客戶端 失去同步。此函式返回後,伺服器就可以接收下一個 SQL 命令了。返回值是 0 表示成功完成,非零表示失敗。(如果返回值非零,請使用 PQerrorMessage 檢索詳細資訊。)

當使用 PQgetResult 時,應用程式應響應 PGRES_COPY_OUT 結果,透過反覆執行 PQgetline,然後在看到終止符行後執行 PQendcopy。然後應返回到 PQgetResult 迴圈,直到 PQgetResult 返回 null 指標。類似地,PGRES_COPY_IN 結果透過一系列 PQputline 呼叫,然後執行 PQendcopy 來處理,然後返回到 PQgetResult 迴圈。這種安排將確保一系列命令中嵌入的 COPY 命令SQL能夠正確執行。

舊的應用程式很可能會透過 PQexec 提交 COPY,並在 PQendcopy 之後假設事務已完成。只有當 COPY 是命令字串中的唯一SQL命令時,這才會正常工作。

提交更正

如果您在文件中發現任何不正確、與您對特定功能的使用經驗不符或需要進一步說明的內容,請使用 此表格 報告文件問題。