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

31.4. 非同期コマンドの処理

PQexec 関数は普通の同期処理のアプリケーションにおけるコマンドの送信に適したものです。 しかし、一部のユーザにとって重要な問題となり得る、数個の問題があります。

アプリケーションにとってこのような制限が望ましくない場合は、代わりに PQexec を構成する関数 PQsendQuery PQgetResult を使用してください。 また、 PQsendQueryParams PQsendPrepare PQsendQueryPrepared PQsendDescribePrepared PQsendDescribePortal もあり、 PQgetResult を使用して、それぞれ PQexecParams PQprepare PQexecPrepared PQdescribePrepared PQdescribePortal と同等の機能を行うことができます。

PQsendQuery

結果を待つことなく、サーバにコマンドを発行します。 コマンドの登録に成功した場合1が、失敗した場合0が返されます。 (後者の場合、 PQerrorMessage を使用して失敗についてのより多くの情報を取り出してください。)

int PQsendQuery(PGconn *conn, const char *command);

PQsendQuery 呼び出しが成功したら、 PQgetResult を繰り返し呼び出して、実行結果を取得します。 PQgetResult がヌルポインタを返し、コマンドが完了したことを示すまでは、(同じ接続で) PQsendQuery を再度呼び出すことはできません。

PQsendQueryParams

結果を待つことなく、サーバにコマンドとパラメータとを分けて発行します。

int PQsendQueryParams(PGconn *conn,
                      const char *command,
                      int nParams,
                      const Oid *paramTypes,
                      const char * const *paramValues,
                      const int *paramLengths,
                      const int *paramFormats,
                      int resultFormat);

これは、問い合わせのパラメータが問い合わせ文字列と分けて指定できる点を除き、 PQsendQuery と同じです。 この関数のパラメータは PQexecParams と同様に扱われます。 PQexecParams 同様、これは2.0プロトコルでは動作しませんし、問い合わせ文字列には1つのコマンドしか指定できません。

PQsendPrepare

指定パラメータを持つプリペアド文の作成要求を送信します。 その完了を待ちません。

int PQsendPrepare(PGconn *conn,
                  const char *stmtName,
                  const char *query,
                  int nParams,
                  const Oid *paramTypes);

これは PQprepare の非同期版です。 要求の登録に成功した場合1が、失敗した場合0が返されます。 呼び出しの成功の後、サーバがプリペアド文の生成に成功したかを確認するためには PQgetResult を呼び出してください。 この関数のパラメータは PQprepare と同様に扱われます。 PQprepare 同様、これは2.0プロトコルの接続では動作しません。

PQsendQueryPrepared

結果を待つことなく、指定したパラメータでプリペアド文の実行要求を送信します。

int PQsendQueryPrepared(PGconn *conn,
                        const char *stmtName,
                        int nParams,
                        const char * const *paramValues,
                        const int *paramLengths,
                        const int *paramFormats,
                        int resultFormat);

これは PQsendQueryParams と似ていますが、実行されるコマンドは問い合わせ文字列ではなく、事前に準備された文の名前で指定されます。 この関数のパラメータは PQexecPrepared と同様に扱われます。 PQexecPrepared 同様、これは2.0プロトコルでは動作しません。

PQsendDescribePrepared

指定したプリペアド文に関する情報入手要求を送ります。 入手完了まで待機しません。

int PQsendDescribePrepared(PGconn *conn, const char *stmtName);

これは PQdescribePrepared の非同期版です。 要求の受付けが可能であれば1が返されます。不可能であれば0が返されます。 呼び出しに成功した後、 PQgetResult を呼び出して結果を入手してください。 この関数のパラメータは PQdescribePrepared と同じように扱われます。 PQdescribePrepared 同様、2.0プロトコル接続では動作しません。

PQsendDescribePortal

指定したポータルに関する情報入手要求を送信します。 完了まで待機しません。

int PQsendDescribePortal(PGconn *conn, const char *portalName);

これは PQdescribePortal の非同期版です。 要求の受付けが可能であれば1が返されます。不可能であれば0が返されます。 呼び出しに成功した後、 PQgetResult を呼び出して結果を入手してください。 この関数のパラメータは PQdescribePortal と同じように扱われます。 PQdescribePortal 同様、2.0プロトコル接続では動作しません。

PQgetResult

以前に呼び出した PQsendQuery PQsendQueryParams PQsendPrepare PQsendQueryPrepared PQsendDescribePrepared PQsendDescribePortal から次の結果を待ち、その結果を返します。 コマンドが完了し、これ以上結果がない場合は、ヌルポインタが返されます。

PGresult *PQgetResult(PGconn *conn);

PQgetResult は、コマンドの完了を示すヌルポインタが返るまで、繰り返し呼び出さなければなりません。 (コマンド実行中以外での呼び出しでは、 PQgetResult は単にヌルポインタを返します。) PQgetResult の非ヌルの結果はそれぞれ前述と同じ PGresult アクセス用関数を使用して処理されなければなりません。 各結果オブジェクトに対する処理が終わったら、そのオブジェクトを PQclear を使用して解放することを忘れないでください。 コマンドが活動中、かつ、必要な応答データがまだ PQconsumeInput で読み込まれていない場合にのみ、 PQgetResult がブロックすることに注意してください。

注意: PQresultStatus が致命的なエラーを示した場合であっても、 libpq がエラー情報を完全に処理できるようにヌルポインタが返されるまで PQgetResult を呼び出さなければなりません。

PQsendQuery PQgetResult を使うことで PQexec の問題は1つ解決します。 つまり、コマンドが複数の SQL コマンドを含んでいる場合でも、これらのコマンドの結果を個々に得ることができるわけです (これは多重処理を単純な形で実現します。 単一のコマンド文字列に含まれる複数の問い合わせの内、後ろのものが処理中でもフロントエンドは先に完了した結果から扱うことができるからです)。

PQsendQuery および PQgetResult で得られる、その他のよく望まれる機能は一度に多くの問い合わせ結果1行で受け取ることです。 これについては 項31.5 で説明します。

サーバが次の SQL コマンドの処理に入ると、それが完了するまでやはり PQgetResult の呼び出しがフロントエンドをブロックしてしまいます。 さらに以下の2つの関数をうまく使用してこれを防ぐことができます。

PQconsumeInput

サーバからの入力が可能になった場合、それを吸い取ります。

int PQconsumeInput(PGconn *conn);

PQconsumeInput は通常、 "エラーなし" を示す1を返しますが、何らかの障害があると0を返します(この場合は、 PQerrorMessage を参考にしてください)。 この結果は、何らかの入力データが実際に収集されたかどうかを示しているのではないことに注意してください。 PQconsumeInput の呼び出し後、アプリケーションは PQisBusy 、または必要があれば PQnotifies を呼び出して状態に変化がないか調べることができます。

PQconsumeInput は、結果や通知を扱うようにまだ準備していないアプリケーションからでも呼び出すことができます。 この関数は有効なデータを読み込んでバッファに保存し、結果として select による読み込み準備完了の通知をリセットします。 従ってアプリケーションは PQconsumeInput を使うと select() の検査条件をただちに満たすことができますから、あとはゆっくりと結果を調べてやればいいわけです。

PQisBusy

この関数が1を返したのであれば、問い合わせは処理の最中で、 PQgetResult も入力を待ったままブロック状態になってしまうでしょう。 0が返ったのであれば、 PQgetResult を呼び出してもブロックされないことが保証されます。

int PQisBusy(PGconn *conn);

PQisBusy 自身はサーバからデータを読み込む操作をしません。 ですから、まず最初に PQconsumeInput を呼び出す必要があります。 そうしないとビジー状態がいつまでも続きます。

これら3関数を使用するアプリケーションは通常、 select() もしくは poll() を使用するメインループを持ち、対応しなければならないすべての状態を待機しています。 その内の1つの条件は、サーバからの利用可能な入力となるでしょう。 これは、 select() の見地からは、 PQsocket で識別されるファイル記述子上で読み込み可能なデータがあることを意味します。 メインループが入力準備完了を検出すると、その入力を読み込むために PQconsumeInput を呼び出さなければなりません。 そして、 PQisBusy を、更に PQisBusy が偽(0)を返す場合に PQgetResult も呼び出すことができます。 また、 PQnotifies を呼び出して、 NOTIFY メッセージ( 項31.8 を参照)を検出することもできます。

また、 PQsendQuery / PQgetResult を使用するクライアントは、サーバで処理中のコマンドに対してキャンセルを試行することができます。 項31.6 を参照してください。 しかし、 PQcancel の戻り値と関係なく、アプリケーションは PQgetResult を使用した通常の結果読み取り手順を続けなければなりません。 キャンセル手続きの成功は単に、そのコマンドを通常よりも早めに終わらせるだけです。

上述の関数を使用して、データベースサーバからの入力待ちのためのブロックを行わずに済みます。 しかしまだ、サーバへの出力送信を待つためにアプリケーションはブロックする可能性があります。 これは比較的あまり発生しませんが、非常に長いSQLコマンドやデータ値が送信される場合に発生することがあります。 (しかし、アプリケーションが COPY IN 経由でデータを送信する場合よく発生します。) この発生を防ぎ、完全な非ブロックのデータベース操作を行うためには、さらに以下の関数を使用してください。

PQsetnonblocking

接続の非ブロック状態を設定します。

int PQsetnonblocking(PGconn *conn, int arg);

arg が1の場合、接続状態を非ブロックに設定します。 arg が0の場合はブロックに設定します。 問題がなければ0が、エラー時は-1が返ります。

非ブロック状態では PQsendQuery PQputline PQputnbytes および PQendcopy の呼び出しはブロックされませんが、再度呼び出さなければならない場合、エラーが返ります。

PQexec は非ブロックモードにはしたがわないことに注意してください。 この関数の呼び出しは、必ずブロック方式で動作します。

PQisnonblocking

データベース接続のブロック状態を返します。

int PQisnonblocking(const PGconn *conn);

接続が非ブロック状態の場合は1が、ブロック状態の場合は0が返ります。

PQflush

キューに蓄えられたサーバへの出力データの吐き出しを行います。 成功時(および送信キューが空の場合)は0が返ります。 何らかの原因で失敗した場合は-1が、送信キュー内のデータをすべて送信できなかった場合は1が返ります。 (これは接続が非ブロックの場合にのみ発生します。)

int PQflush(PGconn *conn);

非ブロック接続時にはコマンドやデータを送信した後に、 PQflush を呼び出してください。 1が返った場合、ソケットの書き込み準備ができるまで待ち、再度呼び出してください。 これを0が返るまで繰り返してください。 PQflush が0を返した後は、ソケットの読み込み準備が整うまで待ち、上述のように応答を読み取ってください。


powered by SEO.CUG.NET