126) The COPY command in Postgres has options to read from or write to the network connection used by libpq. Therefore, functions are necessary to access this network connection directly so applications may take advantage of this capability.
Postgres の COPY コマンドでは, libpq が使っているネットワーク接続に対して読み込み, あるいは書き込みを選ぶことができるようになっています. そこでこのネットワーク接続に直接アクセスするための関数が必要になります. もちろんアプリケーションもこの機能によって恩恵を受けるでしょう.
127) These functions should be executed only after obtaining a PGRES_COPY_OUT or PGRES_COPY_IN result object from PQexec or PQgetResult.
これらの関数は,PQexec または PQgetResult から, PGRES_COPY_OUT か PGRES_COPY_IN 結果オブジェクトを受け取った後にのみ, 実行するべきです.
PQgetline 128) Reads a newline-terminated line of characters (transmitted by the backend server) into a buffer string of size length. 改行で終端する文字列(バックエンドから送信されたもの)を 長さ length のバッファ string に読み込みます.
int PQgetline(PGconn *conn, char *string, int length)129) Like fgets(3), this routine copies up to length-1 characters into string. It is like gets(3), however, in that it converts the terminating newline into a null character. PQgetline returns EOF at EOF, 0 if the entire line has been read, and 1 if the buffer is full but the terminating newline has not yet been read. Notice that the application must check to see if a new line consists of the two characters "\.", which indicates that the backend server has finished sending the results of the copy command. If the application might receive lines that are more than length-1 characters long, care is needed to be sure one recognizes the "\." line correctly (and does not, for example, mistake the end of a long data line for a terminator line). The code in ../src/bin/psql/psql.c contains routines that correctly handle the copy protocol. fgets(3) と同様,このルーチンはバッファに最大 (length-1) 個の文字をコピーしますが,終端の改行が NULL 文字に置き換えられる点では gets(3) に似ています. PQgetline はファイル終端では EOF を,行全体が読み込まれれば 0 を返します. そしてまだ終端の改行が読み込まれていないうちにバッファがいっぱいに なってしまった場合は 1 を返します. アプリケーションは新しく読み込んだ行が, "\." という二文字であるかどうか確認しなければなりません.この二文字は, COPY コマンドの結果をバックエンドサーバが送信し終えたことを示すものです. アプリケーションには,仮に (length-1) 文字より長い行を受け取るようなことがあっても, 間違いなく最終行("\.")を認識するような配慮が必要です. (またたとえば長いデータの行の切れっぱしを,最終行と取りちがえないようにもしてください) プログラム ../src/bin/psql/psql.c が,COPY プロトコルを正しく処理するルーチンを持っています.
PQgetlineAsync 130) Reads a newline-terminated line of characters (transmitted by the backend server) into a buffer without blocking. 改行で終端する行(バックエンドから送信されたもの)を, ブロッキングなしでバッファに読み込みます.
int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)131) This routine is similar to PQgetline, but it can be used by applications that must read COPY data asynchronously, that is without blocking. Having issued the COPY command and gotten a PGRES_COPY_OUT response, the application should call PQconsumeInput and PQgetlineAsync until the end-of-data signal is detected. Unlike PQgetline, this routine takes responsibility for detecting end-of-data. On each call, PQgetlineAsync will return data if a complete newline- terminated data line is available in libpq's input buffer, or if the incoming data line is too long to fit in the buffer offered by the caller. Otherwise, no data is returned until the rest of the line arrives. The routine returns -1 if the end-of-copy-data marker has been recognized, or 0 if no data is available, or a positive number giving the number of bytes of data returned. If -1 is returned, the caller must next call PQendcopy, and then return to normal processing. The data returned will not extend beyond a newline character. If possible a whole line will be returned at one time. But if the buffer offered by the caller is too small to hold a line sent by the backend, then a partial data line will be returned. This can be detected by testing whether the last returned byte is '\n' or not. The returned string is not null-terminated. (If you want to add a terminating null, be sure to pass a bufsize one smaller than the room actually available.) PQgetline と似ていますが,このルーチンは COPY コマンドのデータを非同期的に, つまりブロッキングなしで読み出さなければならないアプリケーションで使います. COPY コマンドを発行し,そして PGRES_COPY_OUT 応答を受け取ったら, アプリケーションはデータ終了の合図を受け取るまで PQconsumeInput と PQgetlineAsync を呼び出し続けます. PQgetline と違い,このルーチンはデータ終了の検出に対して責任を持ちます. PQgetlineAsync が個々の呼び出しでデータを返すのは次の場合です. ひとつはデータ行を,改行終端の完全な形で libpq の入力バッファから取り出すことができる場合. もうひとつは,呼び出し側が用意したバッファでは受信データが長すぎて, 収まりきらない場合です. 一方,このような長い行の残り部分が届かない限りは,何も返しません. このルーチンは,コピーされるデータの終端を示すマークを認識すると -1 を, また何もデータがなければ 0 を,そしてデータを返す場合はそのバイト数を正の値で返します. もし -1 が返されたら,呼び出し側は次に PQendcopy を呼び出さなければなりません. それから通常の処理に戻ります. 返されるデータは改行文字までで,可能であれば行全体を一度に返します. しかし呼び出し側が準備したバッファが少なすぎ, バックエンドから送られてくる行を保持しておくことができない場合には, 部分ごとのデータを返します. これは最後の1バイトが '\n' かどうかを確認すれば検出できます. なお,返される文字列は NULL 終端にはなっていません. (終端 NULL をあとから付け加えるのであれば, ( 実際のバッファサイズ - 1 ) を bufsize として渡すようにしてください)
PQputline 132) Sends a null-terminated string to the backend server. Returns 0 if OK, EOF if unable to send the string. NULL 終端の文字列をバックエンドサーバに送信します. 正常終了なら 0 を返し,文字列を送信できなかった場合は EOF を返します.
int PQputline(PGconn *conn, char *string);133) Note the application must explicitly send the two characters "\." on a final line to indicate to the backend that it has finished sending its data. アプリケーションはデータ送信の完了をバックエンドに示すために, 最終行で "\." の二文字を明示的に送信しなければなりません.
PQputnbytes 134) Sends a non-null-terminated string to the backend server. Returns 0 if OK, EOF if unable to send the string. NULL 終端されていない文字列をバックエンドサーバに送信します. 正常終了なら 0 を返し,文字列を送信できなかった場合は EOF を返します.
int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);135) This is exactly like PQputline, except that the data buffer need not be null-terminated since the number of bytes to send is specified directly. 送信するバイト数を直接指定するので, データバッファが NULL 終端である必要がない点を除けば, これは PQputline と全く同様のものです.
PQendcopy 136) Syncs with the backend. This function waits until the backend has finished the copy. It should either be issued when the last string has been sent to the backend using PQputline or when the last string has been received from the backend using PGgetline. It must be issued or the backend may get "out of sync" with the frontend. Upon return from this function, the backend is ready to receive the next query. The return value is 0 on successful completion, nonzero otherwise. バックエンドと同期します. この関数はバックエンドがコピーを完了するのを待ちます. この関数は PQputline を使ったバックエンドへの文字列送信が完了した時点, あるいは PGgetline を使ったバックエンドからの文字列受信が完了した時点の いずれでも呼び出すべきです.さもないと, バックエンドがフロントエンドとの「同期ずれ」を起こしてしまうかもしれません. この関数から戻った時点で,バックエンドの次の問い合わせを受ける準備が整います. 同期が成功すれば 0 を,そうでなければ 0 以外の値を返します.
int PQendcopy(PGconn *conn);
137) As an example:
一例です :
PQexec(conn, "create table foo (a int4, b char(16), d float8)"); PQexec(conn, "copy foo from stdin"); PQputline(conn, "3\thello world\t4.5\n"); PQputline(conn,"4\tgoodbye world\t7.11\n"); ... PQputline(conn,"\\.\n"); PQendcopy(conn);
138) When using PQgetResult, the application should respond to a PGRES_COPY_OUT result by executing PQgetline repeatedly, followed by PQendcopy after the terminator line is seen. It should then return to the PQgetResult loop until PQgetResult returns NULL. Similarly a PGRES_COPY_IN result is processed by a series of PQputline calls followed by PQendcopy, then return to the PQgetResult loop. This arrangement will ensure that a copy in or copy out command embedded in a series of SQL commands will be executed correctly. Older applications are likely to submit a copy in or copy out via PQexec and assume that the transaction is done after PQendcopy. This will work correctly only if the copy in/out is the only SQL command in the query string.
PQgetResult を使うとき,アプリケーションは PQgetline を繰り返し呼び出して PGRES_COPY_OUT に応答し,最終行を見つけたら続いて PQendcopy を呼び出します. それから,PQgetResult が NULL を返すまで PQgetResult のループに戻っておくべきです. 同じように PGRES_COPY_IN は連続した PQputline で処理し, そして PQendcopy でしめくくった後に PQgetResult のループに戻ります. このようにすることで,ひとつづきの SQL コマンド群に含めたコピーイン/ アウトコマンドを確実に,また正しく実行できるはずです. 比較的古いアプリケーションでは,コピーイン/アウトを PQexec で実行し,PQendcopy の実行でトランザクションは完了する, と想定していることがよくあります. これは文字列中の SQL コマンドが唯一コピーイン/アウトであったときにのみ正しく動作します.