90) The PQexec function is adequate for submitting queries in simple synchronous applications. It has a couple of major deficiencies however:
シンプルな同期型のアプリケーションの場合, 問い合わせの実行は PQexec 関数で十分です. しかし,ここにはいくつか大きな問題があります.
91) PQexec waits for the query to be completed. The application may have other work to do (such as maintaining a user interface), in which case it won't want to block waiting for the response.
PQexec は問い合わせが完了するまで待ち状態になります. この間,アプリケーションには他にするべき作業があるかもしれません (たとえばユーザインターフェースの調整など) このような場合は応答待ちでブロックされたくありません.
92) Since control is buried inside PQexec, it is hard for the frontend to decide it would like to try to cancel the ongoing query. (It can be done from a signal handler, but not otherwise.) ※ but not otherwise -> but, otherwise it is not hard. ?
制御は PQexec 関数の中に埋め込まれてしまっています. したがって,処理中の問い合わせをキャンセルするタイミングを フロントエンド側で判断するのは困難です. (もっとも,シグナルハンドラからは可能ですが)
93) PQexec can return only one PGresult structure. If the submitted query string contains multiple SQL commands, all but the last PGresult are discarded by PQexec.
PQexec が返せる PGresult 構造体はひとつだけです. もし送信した問い合わせ文字列が複数の SQL コマンドを含んでいる場合, PQexec は最後のものだけを除いて,残りすべての PGresult を破棄してしまいます.
94) Applications that do not like these limitations can instead use the underlying functions that PQexec is built from: PQsendQuery and PQgetResult.
アプリケーションにとってこのような制限が望ましくない場合は, かわりに PQexec を構成する内部関数,PQsendQuery と PQgetResult を使ってください.
PQsendQuery 95) Submit a query to Postgres without waiting for the result(s). TRUE is returned if the query was successfully dispatched, FALSE if not (in which case, use PQerrorMessage to get more information about the failure). 結果を待たずに問い合わせを Postgres へ送信します. 問い合わせは直ちに送信され,成功すれば TRUE を,失敗すれば FALSE を返します. (この場合,PQerrorMessage を使えば失敗した理由の詳細を知ることができます)
int PQsendQuery(PGconn *conn, const char *query);96) After successfully calling PQsendQuery, call PQgetResult one or more times to obtain the query results. PQsendQuery may not be called again (on the same connection) until PQgetResult has returned NULL, indicating that the query is done. PQsendQuery 呼び出しが成功したら, PQgetResult をくり返し呼び出して問い合わせ結果を得ます. PQgetResult が NULL を返し,問い合わせが完了したことを示すまでは, 同じ接続で PQsendQuery を呼び出してはいけません.
PQgetResult 97) Wait for the next result from a prior PQsendQuery, and return it. NULL is returned when the query is complete and there will be no more results. 先に実行された PQsendQuery の結果を逐次待ち,その結果を返します. 問い合わせ実行が完了した場合 NULL を返します. NULL が返った場合,取り出す結果はそれ以上ありません.
PGresult *PQgetResult(PGconn *conn);98) PQgetResult must be called repeatedly until it returns NULL, indicating that the query is done. (If called when no query is active, PQgetResult will just return NULL at once.) Each non-null result from PQgetResult should be processed using the same PGresult accessor functions previously described. Don't forget to free each result object with PQclear when done with it. Note that PQgetResult will block only if a query is active and the necessary response data has not yet been read by PQconsumeInput. 問い合わせが完了したことを示す NULL が返るまで, PQgetResult を繰り返して呼び出さなければなりません. (問い合わせがなされていない状態で呼び出すと, PQgetResult はただちに NULL を返すだけです) PQgetResult から得られる(NULL でない)個々の結果は, 前に説明した PGresult のアクセッサ関数と同じものを使って処理してください. 処理が終ったら PQclear を使い, 個々の結果オブジェクトの領域を開放するのを忘れないように. なお問い合わせが実行中であり, かつ PQconsumeInput を使って必要な応答データを読み込んでいない時だけは, PQgetResult が処理をブロックしてしまうことに注意してください.
99) Using PQsendQuery and PQgetResult solves one of PQexec's problems: if a query string contains multiple SQL commands, the results of those commands can be obtained individually. (This allows a simple form of overlapped processing, by the way: the frontend can be handling the results of one query while the backend is still working on later queries in the same query string.) However, calling PQgetResult will still cause the frontend to block until the backend completes the next SQL command. This can be avoided by proper use of three more functions:
PQsendQuery と PQgetResult を使うことで PQexec の問題は一つ解決します. つまり,問い合わせが複数の SQL コマンドを含んでいる場合でも, これらのコマンドの結果を個々に得ることができるわけです. (これは多重処理をシンプルな形で実現します. 単一の文字列に含まれる複数の問い合わせのうち,後にくるものが処理中でも フロントエンドは先に完了した結果から扱うことができるからです) しかしバックエンドが次の SQL コマンドの処理に入ると, それが完了するまでやはり PQgetResult の呼び出しがフロントエンドをブロックしてしまいます. これを防ぐには,さらに三つの関数をうまく使うことです.
PQconsumeInput 100) If input is available from the backend, consume it. バックエンドからの入力が可能になった時点で,それを「吸い取り」ます.
int PQconsumeInput(PGconn *conn);101) PQconsumeInput normally returns 1 indicating "no error", but returns 0 if there was some kind of trouble (in which case PQerrorMessage is set). Note that the result does not say whether any input data was actually collected. After calling PQconsumeInput, the application may check PQisBusy and/or PQnotifies to see if their state has changed. PQconsumeInput may be called even if the application is not prepared to deal with a result or notification just yet. The routine will read available data and save it in a buffer, thereby causing a select(2) read-ready indication to go away. The application can thus use PQconsumeInput to clear the select condition immediately, and then examine the results at leisure. PQconsumeInput は通常,「エラーなし」を示す 1 を返しますが, 何らかの障害があると 0 を返します.(この場合は,PQerrorMessage がセットされます) この結果は何らかの入力データが, 実際に収集されたかどうかを示しているのではないことに注意してください. PQconsumeInput の呼び出し後, アプリケーションは PQisBusy,または必要があれば PQnotifies を呼び出して 状態に変化がないか調べることができます. PQconsumeInput は,結果や通知を扱うようにまだ準備していないアプリケーション からでも呼び出すことができます. このルーチンは有効なデータを読み込んでバッファに保存し, 結果として select(2) による読み込み準備完了の通知をリセットします. したがってアプリケーションは PQconsumeInput を使うと select の検査条件をただちに満たすことができますから, あとはゆっくりと結果を調べてやればいいわけです.
PQisBusy 102) Returns TRUE if a query is busy, that is, PQgetResult would block waiting for input. A FALSE return indicates that PQgetResult can be called with assurance of not blocking. この関数が TRUE を返したのであれば問い合わせは処理の最中で, PQgetResult も入力を待ったままブロック状態になってしまうでしょう. FALSE が返ったのであれば, PQgetResult を呼び出してもブロックされないことが保証されます.
int PQisBusy(PGconn *conn);103) PQisBusy will not itself attempt to read data from the backend; therefore PQconsumeInput must be invoked first, or the busy state will never end. PQisBusy 自身はバックエンドからデータを読み込む操作をしません. ですから,まずは最初に PQconsumeInput を呼び出さなければなりません. さもなければ,ビジー状態がいつまでも続くことになるでしょう.
PQsocket 104) Obtain the file descriptor number for the backend connection socket. A valid descriptor will be >= 0; a result of -1 indicates that no backend connection is currently open. バックエンドとの接続ソケットに対するファイルディスクリプタ番号を得ます. 有効なディスクリプタなら値は 0 以上です. -1 の場合は,バックエンドとの接続がまだオープンされていない, ということを示します.
int PQsocket(PGconn *conn);105) PQsocket should be used to obtain the backend socket descriptor in preparation for executing select(2). This allows an application to wait for either backend responses or other conditions. If the result of select(2) indicates that data can be read from the backend socket, then PQconsumeInput should be called to read the data; after which, PQisBusy, PQgetResult, and/or PQnotifies can be used to process the response. select(2) を実行する際に使うバックエンドへのソケットディスクリプタを得るには, この PQsocket を使います. アプリケーションはこの関数によってバックエンドからの応答, あるいはその他の状態を待つことができるようになります. もし select(2) がバックエンドへのソケットからデータを読み込める状態に なったことを示したら,PQconsumeInput を呼び出してデータを読み込みます. それから PQisBusy, PQgetResult, あるいは必要なら PQnotifies を使って応答を処理します.
106) A typical frontend using these functions will have a main loop that uses select(2) to wait for all the conditions that it must respond to. One of the conditions will be input available from the backend, which in select's terms is readable data on the file descriptor identified by PQsocket. When the main loop detects input ready, it should call PQconsumeInput to read the input. It can then call PQisBusy, followed by PQgetResult if PQisBusy returns FALSE. It can also call PQnotifies to detect NOTIFY messages (see "Asynchronous Notification", below).
これらの関数を使う典型的なフロントエンドは select(2) を使ったメインループを備え, 応答しなければならない全ての状態を待ちます. やがてこの状態のうちひとつ(select 関数の点から見れば, PQsocket で確認したファイルディスクリプタから読み込めるデータ) がバックエンドから入力可能になります. メインループは入力が可能になったことを検出したら, PQconsumeInput を呼び出して入力を読み込みます. 続いて PQisBusy を呼び出し,PQisBusy が FALSE を返したらさらに PQgetResult を呼び出します. あるいは PQnotifies を呼び出して通知メッセージを検出する場合もあります (後出「非同期通知」セクションを参照)
107) A frontend that uses PQsendQuery/PQgetResult can also attempt to cancel a query that is still being processed by the backend.
PQsendQuery/PQgetResult を使うと,バックエンドで処理中の問い合わせを フロントエンドからキャンセルするよう要求することができます.
PQrequestCancel 108) Request that Postgres abandon processing of the current query. Postgres に現在の問い合わせの処理を中断するよう要求します
int PQrequestCancel(PGconn *conn);109) The return value is TRUE if the cancel request was successfully dispatched, FALSE if not. (If not, PQerrorMessage tells why not.) Successful dispatch is no guarantee that the request will have any effect, however. Regardless of the return value of PQrequestCancel, the application must continue with the normal result-reading sequence using PQgetResult. If the cancellation is effective, the current query will terminate early and return an error result. If the cancellation fails (say because the backend was already done processing the query), then there will be no visible result at all. キャンセル要求の受け入れが成功すれば TRUE を,そうでなければ FALSE を返します. (FALSE の場合の理由は PQerrorMessage で知ることができます) しかし要求の受け入れが成功したとしても, その要求の効果が出ることは全く保証していません. したがってアプリケーションは PQrequestCancel の戻り値にかかわらず, PQgetResult を使った通常の結果読み込みシーケンスを継続しなければなりません. もしキャンセル操作が有効であれば現在の問い合わせは間もなく中断され, エラーが結果として返ります. キャンセル操作に失敗した場合 (つまりバックエンドが既に問い合わせ処理を完了していたため) 目に見える結果は何も出てこなくなります.
110) Note that if the current query is part of a transaction, cancellation will abort the whole transaction.
なお,処理中の問い合わせがトランザクションの一部だと, キャンセル処理によってトランザクション全体がアボートされます.
111) PQrequestCancel can safely be invoked from a signal handler. So, it is also possible to use it in conjunction with plain PQexec, if the decision to cancel can be made in a signal handler. For example, psql invokes PQrequestCancel from a SIGINT signal handler, thus allowing interactive cancellation of queries that it issues through PQexec. Note that PQrequestCancel will have no effect if the connection is not currently open or the backend is not currently processing a query.
PQrequestCancel はシグナルハンドラから起動しても大丈夫です. また単に PQexec と組み合わせて使うこともできます. たとえば psql は PQexec を通して発行された問い合わせのキャンセル処理を, SIGINT シグナルハンドラから PQrequestCancel を起動することで インタラクティブに実行できるようになっています. なお,接続がオープンされていない, あるいはバックエンドが問い合わせの処理をしていない状態では, PQrequestCancel の呼び出しは何の効果もありません.