1.4. 非同期問い合わせ関数

シンプルな同期型のアプリケーションの場合。 コマンドの実行は PQexec 関数で十分です。 しかし、大きな問題をいくつか抱えています。

アプリケーションにとってこのような制限が望ましくない場合は、代わりに PQexec を構成する関数 PQsendQueryPQgetResult を使用してください。

PQputlinePQputnbytes と同様に、この機能性を使っている古いプログラムは、バックエンドへのデータ送信待ちをブロックしてしまう可能性がありました。 この問題に対応するために、PQsetnonblocking が追加されました。

古めのアプリケーションでは、PQsetnonblocking が使われていなかったり、昔の潜在的にブロックする挙動を得ていなかったりしました。 新しいプログラムでは、PQsetnonblocking を使用して、バックエンドとの完全に非ブロック状態での接続を実現できます。

PQsendQueryPQgetResult を使うことで PQexec の問題は 1 つ解決します。 つまり、コマンドが複数の SQL コマンドを含んでいる場合でも、これらのコマンドの結果を個々に得ることができるわけです (これは多重処理をシンプルな形で実現します。 単一のコマンド文字列に含まれる複数の問い合わせのうち、後にくるものが処理中でもフロントエンドは先に完了した結果から扱うことができるからです)。 しかしバックエンドが次の SQL コマンドの処理に入ると、それが完了するまでやはり PQgetResult の呼び出しがフロントエンドをブロックしてしまいます。 これを防ぐには、さらに3つの関数をうまく使うことが大切です。

これらの関数を使用するフロントエンドは、select を使ったメインループを備え、応答しなくてはいけないすべての状態を待ちます。 やがてこの状態のうち1つ(select 関数の点から見れば、PQsocket で確認したファイル記述子から読み込めるデータ)がバックエンドから入力可能になります。 メインループは入力が可能になったことを検出したら、PQconsumeInputを呼び出して入力を読み込みます。 続いてPQisBusyを呼び出し、PQisBusyがFALSE(0)を返したら、さらにPQgetResultを呼び出します。 あるいは PQnotifies を呼び出して、通知メッセージを検出する場合もあります(Section 1.6を参照)。

PQsendQuery/PQgetResult を使うと、バックエンドで処理中のコマンドをフロントエンドからキャンセルするよう要求することができます。

なお、処理中のコマンドがトランザクションの一部だと、キャンセル処理によってトランザクション全体がアボートされます。

PQrequestCancel はシグナルハンドラから起動しても大丈夫です。 また、単に PQexec と組み合わせて使うことができます。 たとえば psqlPQexecを通して発行された問い合わせのキャンセル処理を、SIGINT シグナルハンドラから PQrequestCancel を起動することで、対話式に実行できるようになっています。 なお、接続がオープンされていない、あるいはバックエンドがコマンドの処理をしていない状態では、PQrequestCancel の呼び出しは何の効果もありません。