?
本文檔使用
php中文網(wǎng)手冊 發(fā)布
PostgreSQL里的COPY命令里有用于libpq里從網(wǎng)絡(luò)連接讀出或者寫入的選項。 本節(jié)描述的函數(shù)允許應(yīng)用通過提供或者消耗拷貝數(shù)據(jù),充分利用這個功能。
整個過程是應(yīng)用首先通過PQexec
或者一個等效的函數(shù)發(fā)出 SQLCOPY命令。
對這個命令的相應(yīng)(如果命令無誤)將是一個帶著狀態(tài)碼PGRES_COPY_OUT或
者PGRES_COPY_IN的PGresult(具體根據(jù)聲明的拷貝方向)。
應(yīng)用然后就應(yīng)該使用本節(jié)的函數(shù)接受或者發(fā)送數(shù)據(jù)行。在數(shù)據(jù)傳輸結(jié)束之后,
返回另外一個PGresult對象以表明傳輸?shù)某晒蛘呤 ? 它的狀態(tài)將是PGRES_COMMAND_OK表示成功或者如果發(fā)生了一些問題,
是PGRES_FATAL_ERROR。這個時候開始我們可以通過PQexec
發(fā)出更多 SQL 命令
。(在COPY操作在處理的過程中,我們不可能用同一個連接執(zhí)行其它 SQL 命令。
如果一個COPY是通過PQexec
在一個可以包含額外命令的字串里發(fā)出的,
那么應(yīng)用在完成COPY序列之后必須繼續(xù)用PQgetResult
抓取結(jié)果。
只有在PQgetResult
返回NULL的時候,我們才能確信PQexec
的命令字串已經(jīng)處理完畢,
并且已經(jīng)可以安全地發(fā)出更多命令。
本節(jié)地這些函數(shù)應(yīng)該只在從PQexec
或PQgetResult
獲得了PGRES_COPY_OUT或PGRES_COPY_IN結(jié)果狀態(tài)的情況下執(zhí)行。
一個承載了這些狀態(tài)值之一地PGresult對象運載了某些有關(guān)正在開始地COPY操作的額外信息。 這些額外的數(shù)據(jù)可以用那些同時也處理查詢結(jié)果的函數(shù)獲取。
PQnfields
返回要拷貝的字段(數(shù)據(jù)域)個數(shù)。
PQbinaryTuples
0 表示全部拷貝格式都是文本的(行之間用換行分隔,字段用分隔符分隔,等等) 。1 表示全部拷貝格式都是二進(jìn)制。參閱COPY獲取更多信息。
PQfformat
返回和拷貝操作的每個字段相關(guān)的格式代碼(0 是文本,1 是二進(jìn)制)。 如果全部拷貝格式是文本,那么每字段的格式碼將總是零,但是(總體)二進(jìn)制格式可以支持文本和二進(jìn)制字段并存。 (不過,就目前的COPY實現(xiàn),在二進(jìn)制拷貝里只出現(xiàn)二進(jìn)制字段; 所以目前每字段的格式總是匹配縱起格式。)
Note: 注意: 這些額外的數(shù)據(jù)值只能在使用 3.0 版本的協(xié)議的時候獲得。 在使用 2.0 版本的協(xié)議時,所有這些函數(shù)都返回 0。
這些函數(shù)用于在COPY FROM STDIN過程中發(fā)送數(shù)據(jù)。如果在連接不 是處于COPY_IN狀態(tài)下,它們會失敗。
PQputCopyData
在COPY_IN狀態(tài)里向服務(wù)器發(fā)送數(shù)據(jù)完畢的指示。
int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
傳輸指定的buffer里的,長度為nbytes的COPY數(shù)據(jù)到服務(wù)器。
如果數(shù)據(jù)發(fā)送成功,結(jié)果是 1,如果因為發(fā)送企圖會阻塞(這種情況只
有在連接是非阻塞模式時才有可能)而沒有成功,那么是零,或者是在發(fā)
生錯誤的時候是 -1。(如果返回 -1,那么使用PQerrorMessage
檢索細(xì)節(jié)。
如果值是零,那么等待寫準(zhǔn)備好然后重試。)
應(yīng)用可以把COPY數(shù)據(jù)流分隔成任意合適的大小放到緩沖區(qū)里。在發(fā)送的時候, 緩沖區(qū)的邊界沒有什么特殊的語意。數(shù)據(jù)流的內(nèi)容必須匹配COPY命令預(yù)期的數(shù)據(jù)格式; 參閱COPY獲取細(xì)節(jié)。
PQputCopyEnd
在COPY_IN狀態(tài)里向服務(wù)器發(fā)送數(shù)據(jù)完畢的指示。
int PQputCopyEnd(PGconn *conn, const char *errormsg);
如果errormsg是NULL,則成功結(jié)束COPY_IN操作。 如果errormsg不 是NULL則COPY操作被強(qiáng)制失敗,errormsg指向的字串是錯誤信息。 (我們不能認(rèn)為同樣的信息可能會從服務(wù)器傳回,因為服務(wù)器可能已經(jīng)因為自己的原因讓COPY失敗。 還要注意的是在使用 3.0 版本之前的協(xié)議連接時,強(qiáng)制失敗的選項是不能用的。)
如果終止數(shù)據(jù)發(fā)送,則結(jié)果為 1,如果發(fā)送企圖會阻塞(只有在連接是在非阻塞
模式的情況下才可能出現(xiàn)這個情況),則為零,如果發(fā)生錯誤則返回 -1。(如果返回
值是 -1,用PQerrorMessage
檢索細(xì)節(jié)。如果值是零,那么等待寫準(zhǔn)備好然后重新嘗試。)
在成功調(diào)用PQputCopyEnd
之后,調(diào)用PQgetResult
獲取COPY
命令的最終結(jié)果狀態(tài)。
我們可以用平常的方法來等待這個結(jié)果可用。然后返回到正常的操作。
這些函數(shù)用于在COPY TOSTDOUT的過程中檢索數(shù)據(jù)。如果連接不在COPY_OUT狀態(tài),那么他們將會失敗。
PQgetCopyData
在COPY_OUT狀態(tài)下從服務(wù)器接收數(shù)據(jù)。
int PQgetCopyData(PGconn *conn, char **buffer, int async);
在一個COPY的過程中試圖獲取另外一行數(shù)據(jù)。數(shù)據(jù)總是每次返回一個數(shù)據(jù)行;
如果只有一行的部分可用,那么它不會被返回。成功返回一個數(shù)據(jù)行包括分配一個內(nèi)存塊來保存這些數(shù)據(jù)。
buffer參數(shù)必須是非NULL。*buffer設(shè)置為指向分配出來的內(nèi)存的指針,
或者是如果沒有返回緩沖區(qū),那么為NULL。一個非NULL的結(jié)果緩沖區(qū)在不
再需要的時候必須用PQfreemem
釋放。
在成功返回一行之后,那么返回的值就是該數(shù)據(jù)行里數(shù)據(jù)的字節(jié)數(shù)(這個將總是大于零)。
返回的字串總是空結(jié)尾的,雖然可能只是對文本的COPY有用。
一個零的結(jié)果表示該COPY仍然在處理中,但是還沒有可以用的行(這個只有在async為真的時候才可能)。
一個結(jié)果為 -1 的值表示COPY已經(jīng)結(jié)束。結(jié)果為 -2 表示發(fā)生了錯誤(參考PQerrorMessage
獲取原因)。
在async為真的時候(非零),PQgetCopyData 將不會阻塞住等待輸入;
如果該 COPY 仍在處理過程中并且沒有可用的完整行,那么它將返回零。
(在這種情況下它等待讀準(zhǔn)備好,然后在再次調(diào)用PQgetCopyData
之前,調(diào)用 PPQconsumeInput
。)
在async是假(零)的時候,PQgetCopyData
將阻塞住,
知道有可用的數(shù)據(jù)或者操作完成。
在PQgetCopyData
返回 -1 之后,調(diào)用PQgetResult
獲取COPY
命令的最后結(jié)果狀態(tài)。
我們可以用通常的方法等待這個結(jié)果可用。然后返回到正常操作。
下面的這些函數(shù)代表了以前的處理COPY的方法。盡管他們還能用,但是現(xiàn)在已經(jīng)廢棄了, 因為他們的錯誤處理實在是太糟糕了,并且檢測數(shù)據(jù)結(jié)束的方法也很不方便, 并且缺少對二進(jìn)制何非阻塞傳輸?shù)闹С帧?/p>
PQgetline
讀取一個以新行符結(jié)尾的字符行中指定字節(jié)數(shù)的字符(由服務(wù)器服務(wù)器傳輸) 到一個長度為length的字符串緩沖區(qū)。
int PQgetline(PGconn *conn, char *buffer, int length);
這個函數(shù)拷貝最多length-1 個字符到緩沖區(qū)里,然后把終止的新行符轉(zhuǎn)
換成一個字節(jié)零。PQgetline
在輸入結(jié)束時返回EOF,如果整行都被讀取了返回 0,
如果緩沖區(qū)填滿了而還沒有遇到結(jié)束的新行符則返回 1。
注意,應(yīng)用程序必須檢查新行是否包含兩個字符\.,這表明服務(wù)器服務(wù)器 已經(jīng)完成了COPY命令的結(jié)果的發(fā)送。如果應(yīng)用可能收到超過length-1 字符長的字符, 我們就應(yīng)該確保正確識別\.行(例如,不要把一個長的行的結(jié)束當(dāng)作一個終止行)。
PQgetlineAsync
不做阻塞地讀取一行COPY數(shù)據(jù)(由服務(wù)器服務(wù)器傳輸)到一個緩沖區(qū)中。
int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
這個函數(shù)類似于PQgetline
,但是可以用于那些必須異步地讀取COPY數(shù)據(jù)的應(yīng)用,
也就是不阻塞的應(yīng)用。在使用了COPY命令和獲取了PGRES_COPY_OUT響應(yīng)之后,
應(yīng)用應(yīng)該調(diào)用PQconsumeInput
和PQgetlineAsync
直到收到數(shù)據(jù)結(jié)束的信號。
不象PQgetline
,這個函數(shù)負(fù)責(zé)檢測數(shù)據(jù)結(jié)束。
在每次調(diào)用時,如果libpq的輸入緩沖區(qū)內(nèi)有可用的一個完整的換行符結(jié)尾的數(shù)據(jù)行,
PQgetlineAsync
都將返回數(shù)據(jù)。否則,在其他數(shù)據(jù)到達(dá)之前不會返回數(shù)據(jù)。
如果見到了拷貝數(shù)據(jù)結(jié)束的標(biāo)志,此函數(shù)返回 -1,如果沒有可用數(shù)據(jù)返回 0,
或者是給出一個正數(shù)表明返回的數(shù)據(jù)的字節(jié)數(shù)。如果返回 -1,
調(diào)用者下一步必須調(diào)用PQendcopy
,然后回到正常處理。
返回的數(shù)據(jù)將不超過一行的范圍。如果可能,每次將返回一個完整行。 但如果調(diào)用者提供的緩沖區(qū)太小,無法容下服務(wù)器發(fā)出的整行,那么將返回部分行。 這個可以通過測試返回的最后一個字節(jié)是否\n來確認(rèn)。在二進(jìn)制COPY中, 我們需要對COPY數(shù)據(jù)格式進(jìn)行實際的分析,以便做相同的判斷。)返回的字符串不是空結(jié)尾的。 (如果你想得到一個空結(jié)尾的字串,確保你傳遞了一個比實際可用空間少一字節(jié)的bufsize。)
PQputline
向服務(wù)器服務(wù)器發(fā)送一個空結(jié)尾的字符串。成功時返回 0,如果不能發(fā)送字符串返回EOF。
int PQputline(PGconn *conn, const char *string);
一系列PQputline
調(diào)用發(fā)送的COPY數(shù)據(jù)流和PQgetlineAsync
返回的數(shù)據(jù)有著一樣的格式,
只是應(yīng)用不需要明確地在每次PQputline
調(diào)用中發(fā)送一個數(shù)據(jù)行;
我們每次調(diào)用里發(fā)送多行或者部分行都是可以的。
Note: 在PostgreSQL3.0 版本的協(xié)議之前,應(yīng)用必須明確地發(fā)送兩個字符\.給服務(wù)器, 告訴服務(wù)器它已經(jīng)完成COPY數(shù)據(jù)的發(fā)送。雖然這么做仍然有效,但是已經(jīng)廢棄了, \.的特殊含義可能在將來的版本中刪除。在發(fā)送完實際數(shù)據(jù)之后, 調(diào)用
PQendcopy
就足夠了。
PQputnbytes
向服務(wù)器服務(wù)器發(fā)送一個非空結(jié)尾的字符串。成功時返回 0,如果不能發(fā)送字符串返回EOF。
int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
此函數(shù)類似PQputline
,除了數(shù)據(jù)緩沖區(qū)不需要是空結(jié)尾的之外,
因為要發(fā)送的字節(jié)數(shù)是直接聲明的。在發(fā)送二進(jìn)制數(shù)據(jù)的時候使用這個過程。
PQendcopy
與服務(wù)器同步。
int PQendcopy(PGconn *conn);
這個函數(shù)等到服務(wù)器完成拷貝(才返回?)。你可以在用PQputline
向服務(wù)器發(fā)
送完最后一個字符串后或者用PQputline
從服務(wù)器獲取最后一行字符串后調(diào)用它
。我們必須調(diào)用這個函數(shù),否則服務(wù)器可能會和前端"同步丟失""同步丟失"。在這個函數(shù)返回后,
服務(wù)器就已經(jīng)準(zhǔn)備好接收下一個 SQL 命令了。成功時返回0,否則返回非零值。
(如果返回值為非 0,用PQerrorMessage
檢索細(xì)節(jié)。)
在使用PQgetResult
時,應(yīng)用應(yīng)該對PGRES_COPY_OUT的結(jié)果做出反應(yīng):重復(fù)調(diào)用PQgetline
,
并且在收到結(jié)束行時調(diào)用PQendcopy
。然后應(yīng)該返回到PQgetResult
循環(huán)直到PQgetResult
返回 NULL。
類似地,PGRES_COPY_IN結(jié)果是用一系列PQputline
調(diào)用最后跟著PQendcopy
,然后返
回到PQgetResult
循環(huán)。這樣的排列將保證嵌入到一系列SQL命令里的COPY命令將被正確執(zhí)行。
舊的應(yīng)用大多通過PQexec
提交一個COPY命令并且假設(shè)在PQendcopy
. 后事務(wù)完成。
這樣只有在COPY是命令字串里的唯一的SQL命令時才能正確工作。