COPYコマンド関連関数

PostgreSQL 9.0.0文書
前のページ | 巻戻し | 第 31章libpq - C ライブラリ | 早送り | 次のページ

# 31.8. `COPY`コマンド関連関数

PostgreSQLの`COPY`コマンドでは、libpqが使っているネットワーク接続に対して読み込み、あるいは書き込みを選ぶことができるようになっています。 本節で説明する関数により、アプリケーションはコピーするデータの提供やコピーされるデータの使用が可能になるという利点を持ちます。

全体的な処理として、アプリケーションはまず`PQexec`もしくは同等な関数経由で`COPY` SQLコマンドを発行します。 （コマンドでエラーが発生しなければ）この応答は、（指定したコピーの方向に応じて）`PGRES_COPY_OUT`もしくは`PGRES_COPY_IN`という状態コードを持った`PGresult`になります。 その後、アプリケーションは本節の関数を使用して、行データを受信、もしくは、送信しなければなりません。 データの転送が完了した時、転送に成功したか失敗したかを示す別の`PGresult`オブジェクトが返されます。 その状態は、成功時には`PGRES_COMMAND_OK`になり、何らかの問題が起きていた時には `PGRES_FATAL_ERROR`になります。 この時点で、別のSQLコマンドを`PQexec`経由で発行することができます。 （`COPY`操作の実行中は、同じ接続を使用して他のSQLコマンドを実行することはできません。）

`COPY`コマンドが、他にもコマンドを含んだ文字列として`PQexec`経由で発行された場合、アプリケーションは`COPY`処理を終えた後に、`PQgetResult`経由で結果の取り出しを続けなければなりません。 `PQexec`コマンド文字列が完了し、その後のコマンドが安全に発行できることが確実になるのは、`PQgetResult`が`NULL`を返す時のみです。

本節の関数は、`PQexec`もしくは`PQgetResult`から`PGRES_COPY_OUT`もしくは`PGRES_COPY_IN`という結果状態を得た後のみに実行されなければなりません。

これらの状態値の一つを持つ`PGresult`オブジェクトは、開始した`COPY`操作に関する追加データを持ちます。 この追加データは、以下の問い合わせ結果を持つ接続で使用される関数を使用して利用することができます。

`PQnfields`

  コピーされる列(フィールド)数を返します。

`PQbinaryTuples`

  0は、コピー全体の書式がテキスト(改行で区切られた行、区切り文字で区切られた列など)であることを示します。 1は、コピー全体の書式がバイナリであることを示します。 詳細はCOPYを参照してください。

`PQfformat`

  コピー操作対象の列それぞれに関した書式コード(テキストでは0、バイナリでは1)を返します。 コピー全体の書式がテキストの場合は、列単位の書式コードは常にゼロです。 しかし、バイナリ書式はテキスト列もバイナリ列もサポートすることができます。 (しかし、現在の`COPY`実装では、バイナリコピーでのみバイナリ列が発生します。 そのため、今の所列単位の書式は常に全体の書式と一致します。)

> 注意: これらの追加データ値はプロトコル3.0を使用した場合にのみ利用可能です。 プロトコル2.0を使用する場合は、これらの関数は全て0を返します。

## 31.8.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);

  `errormsg`が`NULL`の場合は、`COPY_IN`操作の終了に成功しました。 `errormsg`が`NULL`でない場合は、`COPY`は強制的に失敗されました。 `errormsg`が指し示す文字列はエラーメッセージとして使用されます。 (しかし、このエラーメッセージが正しくサーバから返ったものであるとは仮定すべきではありません。 サーバは既に別の原因で`COPY`に失敗していた可能性があります。 また、この強制的な失敗は3.0より前のプロトコルの接続を使用している場合は動作しません。)

  終端データが送信された場合は結果は1になります。 送信試行がブロックされたため送信できなかった場合はゼロになります。 （これは、接続が非ブロックモードの場合にのみ起こります。） エラーが発生した場合は-1になります。 （戻り値が-1の場合、詳細を取り出すためには`PQerrorMessage`を使用してください。 戻り値がゼロの場合は書き込み準備が整うまで待ち、再実行してください。）

  `PQputCopyEnd`の呼び出しに成功した後、`PQgetResult`を呼び出して`COPY`コマンドの最終的な結果状態を取り出してください。 通常の方法でこの結果が使用できるようになるまで待機しても構いません。 そして、通常の操作に戻ってください。

## 31.8.2. `COPY`データ受信用関数

これらの関数は`COPY TO STDOUT`時にデータを受信するために使用されます。 `COPY_OUT`状態以外の接続で呼び出すと、失敗します。

`PQgetCopyData`

  `COPY_OUT`状態時にサーバからデータを受信します。

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

  `COPY`期間中、サーバから別の行データの入手を試みます。 常に1度に1つの行データが返されます。 部分的な行のみが利用可能な場合は返されません。 行データの取得に成功することは、そのデータを保持するためのメモリチャンクの割り当てを意味します。 `buffer`パラメータは非`NULL`でなければなりません。 `*buffer`は割り当てられたメモリへのポインタに、バッファが返されなかった場合は`NULL`に設定されます。 非`NULL`の結果バッファは、不要になったら`PQfreemem`を使用して解放しなければなりません。

  行の取り込みに成功した時、戻り値は行内のデータのバイト数になります。 (これは常に0より大きくなります。) 返された文字列は常にヌル終端ですが、おそらくテキスト`COPY`でのみ有用になるでしょう。 ゼロという結果は、`COPY`が進行中で、行がまだ利用できない状態であることを示します。 (`async`が真の場合にのみ発生することがあります。) -1という結果は、`COPY`が完了したことを示します。 -2という結果はエラーが発生したことを示します。 (その理由については`PQerrorMessage`を参照してください。)

  `async`が真(非0)の場合、`PQgetCopyData`は入力待ちのためのブロックを行いません。 `COPY`実行中で完全な行を取り出せない場合`PQgetCopyData`は0を返します。 (この場合、再試行の前に読み込み準備が整うまで待機してください。 `PQconsumeInput`を呼び出したかどうかは関係ありません。) `async`が偽(0)の場合、`PQgetCopyData`はデータが利用できるようになるまで、もしくは、操作が完了するまでブロックします。

  `PQgetCopyData`が-1を返した後、`PQgetResult`を呼び出して、`COPY`コマンドの最終結果状態を取り出してください。 通常の方法で結果が利用できるようになるまで待機しても構いません。 そして、通常の操作に戻ってください。

## 31.8.3. 廃れた`COPY`用関数

以下の関数は`COPY`を取扱う、古めの手法を行います。 これらはまだ動作しますが、エラーの取扱いが貧弱であることやデータの終端を検知する方法が不便であることより使用を奨めません。

`PQgetline`

  改行で終端する文字列（サーバから送信されたもの）を長さ`length`のバッファ用文字列に読み込みます。

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

  この関数はバッファに`length`-1個までの文字をコピーし、終端の改行を1バイトのゼロに置き換えます。 `PQgetline`は、入力の終端では`EOF`を、行全体が読み込まれれば0を返します。 そしてまだ終端の改行が読み込まれていないうちにバッファがいっぱいになってしまった場合は1を返します。

  アプリケーションは新しく読み込んだ行が、`\.`という2文字であるかどうか確認しなければいけません。 この2文字は、`COPY`コマンドの結果をサーバが送信し終えたことを示すものです。 アプリケーションには、仮に`length`-1文字より長い行を受け取るようなことがあっても、間違いなく`\.`行を認識するような配慮が必要です （また例えば長いデータの行の終端を、最終行と取り違えないようにもしてください）。

`PQgetlineAsync`

  `COPY`データ行（サーバから送信されたもの）を、ブロッキングなしでバッファに読み込みます。

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

  `PQgetline`と似ていますが、`COPY`のデータを非同期的に、つまりブロッキングなしで読み出さなければならないアプリケーションで使用することができます。 `COPY`コマンドを発行し、そして`PGRES_COPY_OUT`応答を受け取ったら、アプリケーションはデータ終了の合図を受け取るまで`PQconsumeInput`と`PQgetlineAsync`を呼び出します。

  `PQgetline`と違い、この関数はデータ終了の検出に対して責任を持ちます。

  `PQgetlineAsync`の個々の呼び出しでは、libpqの入力バッファ内で完全な行データが利用できる場合にデータを返します。 さもなければ、行の残りが届くまでデータは返されません。 この関数は、コピーデータの終端を示す符号を認識すると-1を、また何もデータがなければ0を、そしてデータを返す場合はそのバイト数を正の値で返します。 もし-1が返されたら、呼び出し側は次に`PQendcopy`を呼び出さなければいけません。 それから通常の処理に戻ります。

  返されるデータは行データの境界を越えて拡張されることはありません。 可能であれば行全体を一度に返します。 しかし呼び出し側が準備したバッファが少なすぎ、サーバから送られてくる行を保持しておくことができない場合には、分割された行データを返します。 テキストデータでは、これは最後の1バイトが`\n`かどうかを確認すれば検出できます。 （バイナリ`COPY`の場合に同様の検出を行うためには、実際に`COPY`データの書式を解析しなければなりません。） なお、返される文字列はヌル終端ではありません。 （ヌル終端を後から付け加えるのであれば、実際に確保するバッファサイズ-1を`bufsize`として渡すようにしてください。）

`PQputline`

  サーバにヌル終端の文字列を送信します。 問題なければ0を返します。 文字列の送信ができなかった場合は`EOF`を返します。

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

  `PQputline`の呼び出しによって送信される`COPY`データストリームは、`PQgetlineAsync`で返される書式と同じ書式を持ちます。 ただし、アプリケーションは、`PQputline`毎に正確に1つのデータ行を送信するように強制されていません。 呼び出し毎に行の一部や複数の行を送信しても問題ありません。

  > 注意: PostgreSQLプロトコル3.0より前では、アプリケーションは、サーバに対して`COPY`データの送信を完了したことを通知するために、最終の行として`\.`という2文字を明示的に送信する必要がありました。 これはまだ動作します。 しかし、これは廃れたものとして、`\.`の特殊な意味は将来のリリースで無くなることが予想されます。 実際のデータの送信完了後に`PQendcopy`を呼び出すことが重要です。

`PQputnbytes`

  ヌル終端ではない文字列をサーバに送信します。 問題なければ0を返します。 文字列の送信ができなかった場合は`EOF`を返します。

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

  これはまさに`PQputline`と同様です。 ただし、直接送信バイト数を指定するため、ヌル終端である必要がありません。 バイナリデータを送信する時はこのプロシージャを使用してください。

`PQendcopy`

  サーバと同期します。

      int PQendcopy(PGconn *conn);

  この関数はサーバがコピーを完了するのを待ちます。 この関数は、`PQputline`を使ったサーバへの文字列送信が完了した時点、あるいは`PGgetline`を使ったサーバからの文字列受信が完了した時点のいずれでも呼び出さなければなりません。 これを発行しないと、サーバはクライアントとの"同期がずれた"状態になってしまいます。 この関数から戻った時点で、サーバは次のSQLコマンドを受ける準備が整います。 正常に終了した場合、返り値は0です。 さもなくば、非ゼロです。 （戻り値が非ゼロの場合、`PQerrorMessage`を使用して詳細を取り出してください。）

  `PQgetResult`を使う場合、アプリケーションは`PQgetline`を繰り返し呼び出して`PGRES_COPY_OUT`に応答し、終端行を見つけたら続いて`PQendcopy`を呼び出さなければなりません。 それから、`PQgetResult`がヌルポインタを返すまで、`PQgetResult`のループに戻らなければなりません。 同じように `PGRES_COPY_IN`は連続した`PQputline`で処理し、それから`PQendcopy`で締めくくった後に`PQgetResult`のループに戻ります。 このようにすることで、一連のSQLコマンド群に含めた`COPY`コマンドを確実に、また正しく実行できるはずです。

  比較的古いアプリケーションでは、`COPY`を`PQexec`で実行し、`PQendcopy`の実行でトランザクションは完了する、と想定していることがよくあります。 これはコマンド文字列中のSQLが`COPY`だけであった時にのみ正しく動作します。

前のページ | ホーム | 次のページ
非同期通知 | 上に戻る | 制御関数