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