無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

31.9. 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.9.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.9.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.9.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 だけであった時にのみ正しく動作します。


powered by SEO.CUG.NET