本節では、メッセージの流れと各メッセージ種類のセマンティックスを説明します。 (各メッセージの正確な表現の詳細は項44.4で説明します。) 開始、問い合わせ、関数呼出し、COPY、終了といった接続状態に応じて、複数の異なるサブプロトコルがあります。 また、開始段階の後の任意の時点で発生する可能性がある、非同期操作(通知応答やコマンドのキャンセルを含む)用の特別な準備もあります。
セッションを始めるために、フロントエンドはサーバへの接続を開き、開始メッセージを送信します。 このメッセージには、ユーザ名と接続を希望するデータベース名が含まれます。 これはまた、使用する特定のプロトコルバージョンを識別します。 (オプションとして、開始メッセージに、実行時パラメータの追加設定を含めることもできます。) サーバはその後、この情報と設定ファイル(pg_hba.confなど)の内容を使用して、接続が仮に受け付けることができるかどうか、(もしあれば)どのような追加認証が必要かを決定します。
サーバはその後、適切な認証要求メッセージを送信します。 フロントエンドはこれに適切な認証応答メッセージ(パスワードなど)で応えなければなりません。 原則として、認証要求/応答サイクルは複数回繰り返すことを必要とすることができますが、1つ以上の要求と応答を使用する認証方式は現在存在しません。 認証方式の中には、フロントエンドからの応答を全く必要としないものもあり、その場合、認証要求も発生しません。
認証サイクルは、サーバによって接続要求を拒絶する(ErrorResponse)か、あるいはAuthenticationOkを送信することで終ります。
この段階でサーバから送信される可能性があるメッセージを以下に示します。
接続試行が拒絶されました。 サーバはその後即座に接続を閉ざします。
認証情報の交換が正常に完了しました。
フロントエンドはここでサーバとのKerberos V4認証ダイアログ(ここでは説明しません。Kerberos仕様の一部)に参加する必要があります。 これが成功すれば、サーバはAuthenticationOk応答を行ないます。 失敗すれば、ErrorResponse応答を行ないます。
フロントエンドはここでサーバとのKerberos V5認証ダイアログ(ここでは説明しません。Kerberos仕様の一部)に参加する必要があります。 これが成功すれば、サーバはAuthenticationOk応答を行ないます。 失敗すれば、ErrorResponse応答を行ないます。
フロントエンドはここで平文形式のパスワードを含むPasswordMessageを送信する必要があります。 これが正しいパスワードであればサーバはAuthenticationOk応答を行ないます。 さもなくば、ErrorResponse応答を行ないます。
フロントエンドはここでAuthenticationCryptPasswordメッセージで指定された2文字をソルトに使用するcrypt(3)で暗号化されたパスワードを含むPasswordMessageを送信する必要があります。 これが正しいパスワードであればサーバはAuthenticationOk応答を行ないます。 さもなくば、ErrorResponse応答を行ないます。
フロントエンドはここでAuthenticationMD5Passwordメッセージで指定された4文字をソルトに使用するMD5で暗号化されたパスワードを含むPasswordMessageを送信する必要があります。 これが正しいパスワードであればサーバはAuthenticationOk応答を行ないます。 さもなくば、ErrorResponse応答を行ないます。
この応答はSCM資格証明メッセージをサポートするプラットフォーム上のローカルなUnixドメイン接続でのみあり得ます。 フロントエンドはSCM資格証明メッセージを発行し、その後単一のデータバイトを送信する必要があります。 (データバイトの内容には意味はありません。これはサーバが資格証明メッセージの受信にどれだけ待機すればいいのかを確実にするためだけに使用されます。) 資格証明が受け付け可能であればサーバはAuthenticationOk応答を行ないます。 さもなくば、ErrorResponse応答を行ないます。
フロントエンドが、サーバが要求した認証方式をサポートしていない場合、フロントエンドは即座に接続を閉ざします。
AuthenticationOkを受けとった後、フロントエンドは更にサーバからのメッセージを待機する必要があります。 この段階で、バックエンドプロセスが起動し、このフロントエンドは単なる興味を持った傍観者でしかありません。 開始試行が失敗(ErrorResponse)する可能性がまだありますが、通常、バックエンドは何からのParameterStatusメッセージ、BackendKeyData、最後にReadyForQueryを送信します。
この段階の期間中、バックエンドは開始メッセージで与えられた任意の実行時パラメータの追加設定を適用しようとします。 成功した場合は、これらの値はセッションのデフォルトになります。 エラーが発生した場合はErrorResponseを行ない、終了します。
この段階でバックエンドから送信される可能性があるメッセージを以下に示します。
このメッセージは、フロントエンドがキャンセル要求を後で送信できるようにしたい場合に保存しなければならない、秘密キーデータを提供します。 フロントエンドはこのメッセージに応答すべきではありません。 ReadyForQueryメッセージの監視を続けるべきです。
このメッセージは、フロントエンドに現在(初期)のclient_encodingやDateStyleなどのバックエンドパラメータの設定情報を通知します。 フロントエンドはこのメッセージを無視しても、将来の使用に備えてその設定を記録しても構いません。 より詳細は項44.2.6を参照してください。 フロントエンドはこのメッセージに応答すべきではありません。 ReadyForQueryメッセージの監視を続けるべきです。
開始処理が完了しました。 フロントエンドはここでコマンドを発行することができます。
開始処理が失敗しました。 接続はこのメッセージの送信後に閉ざされます。
警告メッセージが発行されました。 フロントエンドはこのメッセージを表示し、ReadyForQueryもしくはErrorResponseメッセージの監視を続けるべきです。
ReadyForQueryメッセージは各コマンドサイクルの後にバックエンドが発行するものと同じものです。 フロントエンドのコーディングにおいて必要であれば、ReadyForQueryをコマンドサイクルの開始と見做しても構いませんし、ReadyForQueryを開始段階とその後の各コマンドサイクルの終端と見做しても構いません。
フロントエンドがQueryメッセージをバックエンドに送信することで、簡易問い合わせサイクルが初期化されます。 このメッセージには、テキスト文字列で表現されたSQLコマンド(またはコマンド)が含まれます。 その後バックエンドは、問い合わせコマンド文字列の内容に応じた1つ以上の応答を送信します。 ReadyForQueryは、新しいコマンドを安全に送信できることをフロントエンドに伝えます。 (実際には、フロントエンドが他のコマンドを発行する前にReadyForQueryを待機することは不要です。 しかし、フロントエンドは、前のコマンドが失敗し、発行済みの後のコマンドが成功した場合に何が起きるかを了解する責任を持たなければなりません。)
バックエンドから送信される可能性がある応答メッセージを以下に示します。
SQLコマンドが正常に終了しました。
バックエンドがフロントエンドからのデータをテーブルにコピーする準備ができました。 項44.2.5を参照してください。
バックエンドがデータをテーブルからフロントエンドにコピーする準備ができました。 項44.2.5を参照してください。
応答として返す行がSELECTやFETCHなどの問い合わせの結果であることを通知します。 このメッセージには、行の列レイアウトに関する説明が含まれます。 このメッセージの後に、フロントエンドに各行を返すためのDataRowメッセージが続きます。
SELECTやFETCHなどで返される行の集合の1つです。
空の問い合わせ文字列が検知されました。
エラーが起こりました。
問い合わせ文字列の処理が終了しました。 問い合わせ文字列は複数のSQLコマンドが含まれる場合があるため、このことを通知するために分離したメッセージが送出されます。 (CompletedResponseは文字列全体ではなく、1つのSQLコマンドの処理の終了を意味します。) 処理が成功またはエラーで終了したかどうかにかかわらずReadyForQueryは常に送出されます。
問い合わせに関して警告メッセージが発行されました。 警告メッセージは他の応答に対する追加のメッセージです。 従って、バックエンドはそのコマンドの処理を続行します。
SELECT問い合わせ(あるいは、EXPLAINやSHOWなどの行集合を返す他の問い合わせ)に対する応答は、通常、RowDescription、0個以上のDataRowメッセージ、その後にCommandCompleteから構成されます。 フロントエンドへCOPYもしくはフロントエンドからのCOPYは項44.2.5で説明する特別なプロトコルを呼び出します。 他の種類の問い合わせは通常CommandCompleteメッセージのみを生成します。
問い合わせ文字列には(セミコロンで区切られた)複数の問い合わせが含まれることがありますので、バックエンドが問い合わせ文字列の処理を完了する前に、こうした応答シーケンスが複数発生する可能性があります。 ReadyForQueryは、文字列全体が処理され、バックエンドが新しい問い合わせ文字列を受け付ける準備が整った時点で発行されます。
完全に空の(空白文字以外の文字がない)問い合わせ文字列を受け取った場合、その応答は、EmptyQueryResponse、続いて、ReadyForQueryとなります。
エラーが発生した場合、ErrorResponse、続いて、ReadyForQueryが発行されます。 その問い合わせ文字列に対する以降の処理は(複数の問い合わせが残っていたとしても)全て、ErrorResponseによって中断されます。 これは、個々の問い合わせで生成されるメッセージのシーケンスの途中で発生する可能性があることに注意して下さい。
簡易問い合わせモードでは、受信する値の書式は常にテキストです。 ただし、与えられたコマンドがBINARYオプション付きで宣言されたカーソルからのFETCHであった場合は例外です。 この場合は、受信する値はバイナリ書式になります。 RowDescriptionメッセージ内で与えられる書式コードは、どの書式が使用されているかを通知します。
フロントエンドは他の種類のメッセージの受信を待機している時は常にErrorResponseとNoticeResponseメッセージを受け取る準備ができていなければなりません。 また、外部イベントのためにバックエンドが生成する可能性があるメッセージの扱いについて項44.2.6を参照してください。
メッセージの正しい並びを前提としてコーディングするのではなく、任意のメッセージ種類を、そのメッセージが意味を持つ任意の時点で受け付ける状態マシン形式でフロントエンドのコーディングを行なうことを推奨します。
拡張問い合わせプロトコルは、上述の簡易問い合わせプロトコルを複数段階に分解します。 予備段階の結果は複数回最利用できますので、効率が上がります。 更に、問い合わせ文字列に直接埋め込むのではなく、データ値をパラメータとして分離して提供できる機能など、利用できる追加機能があります。
拡張プロトコルでは、フロントエンドはまず、テキストの問い合わせ文字列とオプションとしてパラメータプレースホルダのデータ型情報やプリペアドステートメントオブジェクトの宛先名(空文字列は無名のプリペアドステートメントを選択)を含む、Parseメッセージを送信します。 この応答はParseCompleteまたはErrorResponseです。 パラメータデータ型はそのOIDで指定することができます。 指定がなければ、パーサは型指定のないリテラル文字列定数に対する方法と同じ方法でデータ型を推定します。
注意: Parseメッセージ内の問い合わせ文字列には、複数のSQL文を含めることはできません。 さもなくば、構文エラーが報告されます。 この制限は簡易問い合わせプロトコルにはありませんが、複数のコマンドを持つプリペアドステートメントやポータルを許すと、プロトコルが複雑になり過ぎるため、拡張プロトコルではこの制限があります。
作成に成功すると、名前付きプリペアドステートメントオブジェクトは明示的に破棄されない限り現在のセッションが終るまで残ります。 無名プリペアドステートメントオブジェクトは、次に無名プリペアドステートメントを宛先に指定したParse文が発行されるまでの間のみに残ります。 (単なるQueryメッセージでも無名のプリペアドステートメントオブジェクトは破壊されることに注意してください。) 名前付きプリペアドステートメントは、Parseメッセージで再定義する前に明示的に閉じなければなりません。 しかし、これは無名プリペアドステートメントでは必要ありません。 名前付きプリペアドステートメントはまた、SQLコマンドレベルでPREPAREとEXECUTEを使用して作成しアクセスすることができます。
プリペアドステートメントが存在すると、Bindメッセージを使用してそれを実行可能状態にすることができます。 Bindメッセージは、元となるプリペアドステートメント(空文字列は無名プリペアドステートメントを表します)、宛先となるポータル(空文字列は無名ポータルを表します)、およびプリペアドステートメント内のパラメータプレースホルダに使用する値を与えます。 与えられたパラメータ集合はプリペアドステートメントで必要とするものと一致しなければなりません。 また、Bindは問い合わせで返されるデータに使用する書式を指定します。 書式は全体に対して指定することも、列単位で指定することも可能です。 応答はBindCompleteもしくはErrorResponseです。
注意: テキスト出力とバイナリ出力との選択は、含まれるSQLコマンドに関係なく、Bindで与えられた書式コードで決定されます。 拡張問い合わせプロトコルを使用する場合、カーソル宣言のBINARY属性は役に立ちません。
作成に成功すると、名前付きポータルオブジェクトは明示的に破棄されない限り現在のセッションが終るまで残ります。 無名ポータルは、トランザクションの終り、もしくは、次に無名ポータルを宛先に指定したParse文が発行されるまでの間のみに残ります。 (単なるQueryメッセージでも無名ポータルは破壊されることに注意してください。) 名前付きポータルは、Bindメッセージで再定義する前に明示的に閉じなければなりません。 しかし、これは無名ポータルでは必要ありません。 名前付きポータルはまた、SQLコマンドレベルでDECLARE CURSORとFETCHを使用して作成しアクセスすることができます。
ポータルが存在すると、Executeメッセージを使用してそれを実行することができます。 Executeメッセージは、ポータル名(空文字列は無名ポータルを表します)と結果行の最大数(ゼロは"fetch all rows"を意味します)を指定します。 結果行数は、ポータルが含むコマンドが行集合を返す場合のみ意味があります。 その他の場合では、コマンドは終りまで実行され、行数は無視されます。 Executeで起こり得る応答は、ExecuteではReadyForQueryが発行されない点を除き、上述の簡易問い合わせプロトコル経由で発行された問い合わせの場合と同じです。
Executeがポータルの実行が完了する前に(非0の結果行数に達したために)終了した場合、PortalSuspendedを送信します。 このメッセージの出現は、フロントエンドに操作を完了させるためには同一のポータルに対して、別のExecuteを発行しなければならないことを通知します。 元となったSQLコマンドが完了したことを示すCommandCompleteメッセージはポータルが完了するまで送信されません。 そ違って、Execute段階は常にCommandComplete、EmptyQueryResponse (空の問い合わせ文字列からポータルが作成された場合)、ErrorResponse、PortalSuspendedの内、正確に1つの出現によって終了します。
拡張問い合わせメッセージの一連の流れのそれぞれの終了時、フロントエンドはSyncメッセージを発行すべきです。 このパラメータのないメッセージにより、バックエンドは、もしBEGIN/COMMITトランザクションブロックの内部でなければ、現在のトランザクションを閉ざします。 ("閉ざす"とは、エラーがなければコミット、エラーがあればロールバックすることを意味します。) そして、ReadyForQuery応答が発行されます。 Syncの目的は、エラーからの復旧用の再同期を行なう時点を提供することです。 拡張問い合わせメッセージの処理中にエラーが検出されると、バックエンドはErrorResponseを発行し、Syncが届くまでメッセージを読み、それを破棄します。 その後、ReadyForQueryを発行し、通常のメッセージ処理に戻ります。 (しかし、Sync処理中にエラーが検出された場合は処理が飛ばされてしまうことに注意してください。 これにより、各Syncに対してReadyForQueryが1つのみであることを確実にします。)
注意: Syncによって、BEGINで開かれたトランザクションブロックが閉ざされることはありません。 ReadyForQueryメッセージにはトランザクションの状態情報が含まれていますので、この状況を検出することができます。
これらの基本的な必要操作に加え、拡張問い合わせプロトコルで使用することができる、複数の省略可能な操作があります。
Describeメッセージ(ポータルの亜種)は、既存のポータルの名前(もしくは、無名ポータル用の空文字)を指定します。 応答は、実行中のポータルで返される予定の行を記述するRowDescriptionメッセージです。 ポータルが行を返す問い合わせを含まない場合はNoDataメッセージです。 指定したポータルが存在しない場合はErrorResponseです。
Describeメッセージ(ステートメントの亜種)は、既存のプリペアドステートメントの名前(もしくは無名プリペアドステートメント用の空文字)を指定します。 応答は、ステートメントで必要とされるパラメータを記述するParameterDescriptionメッセージ、続いて、文が実行された場合に返される予定の行を記述するRowDescriptionメッセージ(もしくは文が行を返さない場合のNoDataメッセージ)です。 指定したプリペアドステートメントが存在しない場合はErrorResponseが発行されます。 Bindがまだ発行されていませんので、返される列の書式はまだバックエンドでは不明であることに注意してください。 RowDescriptionメッセージ内の書式コードフィールドはこの場合はゼロになります。
ティップ: ほとんどの状況では、フロントエンドはExecuteを発行する前に、返ってくる結果を解釈する方法を確実に判断できるように、あるDescribeもしくはその亜種を実行すべきです。
Closeメッセージは、既存のプリペアドステートメント、もしくはポータルを閉ざし、リソースを解放します。 存在しないステートメントやポータルに対してCloseを発行してもエラーになりません。 応答は通常CloseCompleteですが、リソースの解放に何らかの問題が発生した場合はErrorResponseになります。 プリペアドステートメントを閉じると、そこから構築され、開いたポータルが暗黙的に閉ざされることに注意してください。
Flushメッセージにより特定の出力を生成されることはありません。 しかし、バックエンドに対して、出力バッファ内で待機しているデータを強制的に配送させます。 フロントエンドが他のコマンドを発行する前にコマンドの結果を検証したい場合に、FlushはSync以外の拡張問い合わせコマンドの後に送信される必要があります。 Flushを行なわないと、バックエンドで返されるメッセージは、ネットワークオーバーヘッドを最小化する、最低のパケット数にまとめられます。
注意: 簡易問い合わせメッセージは、おおよそ、無名のプリペアドステートメントとポータルオブジェクトを使用したパラメータなしのParse、Bind、ポータル用Describe、Execute、Close、SYncの流れと同一です。 違いは、問い合わせ文字列内に複数のSQL文を受け付けられ、bind/describe/executeという流れがそれぞれが成功すれば自動的に行なわれる点です。 他の違いとして、ParseCompleteやBindComplete、CloseComplete、NoDataメッセージが返されない点があります。
関数呼出しサブプロトコルにより、クライアントはデータベースのpg_procシステムカタログに存在する任意の関数を直接呼び出す要求を行なうことができます。 クライアントはその関数を実行する権限を持たなければなりません。
注意: 関数呼出しサブプロトコルは、おそらく新規のコードでは使用すべきではない、古い機能です。 同様の結果は、SELECT function($1, ...)を行なうプリペアドステートメントを設定することで得ることができます。 そして、この関数呼出しサイクルをBind/Executeで置き換えることができます。
関数呼び出しサイクルはフロントエンドがFunctionCallメッセージをバックエンドに送ることで起動されます。 バックエンドは1つまたは複数の応答メッセージを関数呼び出しの結果に基づいて送り、最終的にReadyForQueryメッセージを送出します。 ReadyForQueryはフロントエンドに対し新規の問い合わせまたは関数呼び出しを行っても安全確実であることを通知します。
バックエンドから送信される可能性がある応答メッセージを以下に示します。
エラーが起こりました。
関数呼び出しが完了し結果がメッセージ内に返されました。 (関数呼出しプロトコルは単一のスカラ結果のみを扱うことができます。行型や結果集合を扱うことはできません。)
関数呼び出しの処理が終了しました。 処理が成功またはエラーで終了したかどうかにかかわらずReadyForQueryは常に送出されます。
関数呼び出しに関して警告メッセージが出されました。 警告メッセージは他の応答に対する追加のメッセージです。 従って、バックエンドはそのコマンドの処理を続行します。
COPYコマンドにより、サーバとの間で高速な大量データ転送を行なうことができます。 コピーインとコピーアウト操作はそれぞれ接続を別のサブプロトコルに切替えます。 これは操作が完了するまで残ります。
コピーインモード(サーバへのデータ転送)は、バックエンドがCOPY FROM STDIN SQLコマンドを実行した時に起動されます。 バックエンドはフロントエンドにCopyInResponseメッセージを送信します。 フロントエンドはその後、0個以上のCopyDataメッセージを送信し、入力データのストリームを形成します。 (結構合理的な選択ではありますが、このメッセージの境界は行の境界を行なうものを持つ必要はありません。) フロントエンドは、CopyDoneメッセージ(正常に終了させる)、もしくは、CopyFailメッセージ(COPY SQL文をエラーで失敗させる)を送信することで、コピーインモードを終了させることができます。 そして、バックエンドは、COPYが始まる前の、簡易もしくは拡張問い合わせプロトコルを使用するコマンド処理モードに戻ります。 そして次に、CommandComplete(成功時)またはErrorResponse(失敗時)のどちらかを送信します。
コピーインモードの期間中にバックエンドがエラー(CopyFailメッセージの受信を含む)を検知すると、バックエンドはErrorResponseメッセージを発行します。 拡張問い合わせメッセージ経由でCOPYコマンドが発行された場合、バックエンドはSyncメッセージを受けとるまでフロントエンドのメッセージを破棄するようになります。 Syncメッセージを受けとると、ReadyForQueryを発行し、通常処理に戻ります。 簡易問い合わせメッセージ経由でCOPYが発行された場合、メッセージの残りは破棄され、ReadyForQueryメッセージを発行します。 どちらの場合でも、その後にフロントエンドによって発行されたCopyData、CopyDone、CopyFailは単に削除されます。
バックエンドは、コピーインモード期間中、FlushとSyncメッセージを無視します。 その他の種類の非コピーメッセージを受けとると、エラーになり、上述のようにコピーイン状態を中断します。 (クライアントライブラリがExecuteメッセージの後に、実行したコマンドがCOPY FROM STDINかどうかを検索することなく、常にFlushまたはSyncを送信できる、という便利さのためにFlushとSyncは例外です。)
コピーアウトモード(サーバからのデータ転送)は、バックエンドがCOPY TO STDOUT SQL文を実行した時に起動します。 バックエンドはCopyOutResponseメッセージをフロントエンドに送信し、その後、0個以上のCopyDataメッセージ(常に行毎に1つ)を、そして、CopyDoneを送信します。 その後、バックエンドはCOPYが始まる前のコマンド処理モードに戻り、CommandCompleteを送信します。 フロントエンドは、(接続の切断やCancel要求の発行は例外ですが)転送を中断することはできません。 しかし、不要なCopyDataとCopyDoneメッセージを破棄することは可能です。
コピーアウトモード期間中バックエンドはエラーを検知すると、ErrorResponseメッセージを発行し、通常処理に戻ります。 フロントエンドはErrorResponse(というより実際はCopyDataとCopyDone以外のメッセージ種類)の受信をコピーアウトモードの終了として扱うべきです。
CopyInResponseとCopyOutResponseメッセージには、フロントエンドに1行当たりの列数と各列で使用する書式コードを通知するためのフィールドが含まれています。 (現在の実装では、COPY操作で与えられるすべての列は同一の書式を使用します。 しかし、メッセージの設計においては、これを前提としていません。)
バックエンドが、フロントエンドのコマンドストリームで特に依頼されていないメッセージを送信する場合が複数あります。 フロントエンドは、問い合わせ作業を行なっていない時であっても常に、これらのメッセージを扱う準備をしなければなりません。 少なくとも、問い合わせの応答の読み込みを始める前にこれらを検査すべきです。
外部の活動によって、NoticeResponseメッセージを生成することが可能です。 例えば、データベース管理者が"高速"データベース停止コマンドを実行した場合、バックエンドは接続を閉ざす前にこれを通知するためにNoticeResponseを送信します。 従って、たとえ接続が名のみの待機状態であったとしても、フロントエンドは常にNoticeResponseメッセージを受け付け、表示する準備をすべきです。
ParameterStatusメッセージは、任意のパラメータの実際の値が変更され、それをバックエンドがフロントエンドに通知するべきであると見做した場合は常に生成されます。 ほとんどの場合、これはフロントエンドによるSET SQLコマンド実行に対する応答の中で起こります。 これは実質的には同期していますが、管理者が設定ファイルを変更し、SIGHUPシグナルをpostmasterに送った場合にも、パラメータ状態の変更が発生することがあります。 また、SETコマンドがロールバックされた場合、現在の有効値を報告するために適切なParameterStatusメッセージが生成されます。
現時点では、ParameterStatusを生成するパラメータ群は固定されています。 それはserver_version(起動後変更できない疑似パラメータ)、client_encoding、is_superuser、session_authorizationおよびDateStyleです。 これは今後変更される、あるいは、設定変更可能になる可能性があります。 従って、フロントエンドは解釈しないParameterStatusを単に無視すべきです。
フロントエンドがLISTENコマンドを発行した場合、同じ通知名に対しNOTIFY コマンドが実行された時にバックエンドはNofificationResponseメッセージ(NoticeResponseと間違えないように!)を送出します。
注意: 現在、NotificationResponseをトランザクションの外部でのみ送信することができます。 このため、これはコマンド応答の流れの途中では起こりませんが、ReadyForQueryの直前に発生する可能性があります。 しかし、これを前提にフロントエンドのロジックを設計することは避けてください。 プロトコル内の任意の時点でNotificationResponseを受け付けられるようにすることを勧めます。
問い合わせの処理中に、フロントエンドは問い合わせを取り消すことができます。 取り消し要求は、効率を高めるために、接続を開いたバックエンドに対して直接送信されません。 その問い合わせを処理中のバックエンドが、フロントエンドからの新しい入力があるかどうかを定期的に確認することは好ましくありません。 取り消し要求はたいていの場合、頻繁には起こらないので、通常の状態においての負担を避けるため、多少扱いにくくなっています。
取り消し要求を出す場合、フロントエンドは通常の新規接続のときに送出されるStartupMessageメッセージではなくCancelRequestメッセージをサーバに送り、新規接続を開始します。 サーバはこの要求を処理し、接続を切断します。 セキュリティ上の理由から、取り消し要求メッセージに対し直接の回答はありません。
CancelRequestメッセージは、接続開始段階でフロントエンドに送られたのと同一の鍵データ(PIDと秘密鍵)を含んでいない場合は無視されます。 現在バックエンドが実行中の処理に対するPIDと秘密鍵が要求と一致した場合、その現在の問い合わせ処理は中断されます。 (現状では、これは、その問い合わせを処理しているバックエンドプロセスに対し特別なシグナルを送ることで実装されています。)
この取り消し信号は何の効果も生まないことがあります。 たとえば、バックエンドが問い合わせの処理を完了した後に届いた場合、効果がありません。 もし取り消し処理が有効であれば、エラーメッセージとともに、現在の命令は終了されます。
セキュリティと効率の理由による上述の実装の結果、フロントエンドは取り消し要求が成功したかどうかを直接判断することはできません。 フロントエンドはバックエンドからの問い合わせの回答を待ち続けなければいけません。 取り消しを要求することは単に現在の問い合わせを早めに終わらせ、成功ではなくエラーメッセージを出して不成功とする可能性を多少高める程度のものです。
取り消し要求は、通常のフロントエンドとバックエンドの通信接続を通してではなく新規のサーバとの接続に送られるため、取り消される問い合わせを実行したフロントエンドだけでなく、任意のプロセスによっても出される可能性があります。 このことはマルチプロセスアプリケーションを作るに当たって柔軟性を提供します。 同時に、承認されていない者が問い合わせを取り消そうとするといったセキュリティ上のリスクも持ち込みます。 このセキュリティ上のリスクは、取り消し要求内に動的に生成される秘密キーを供給することを必須とすることで回避されます。
通常の洗練された終了手順はフロントエンドがTerminateメッセージを出し、すぐに接続を閉じることです。 このメッセージを受け取るとすぐにバックエンドは接続を閉じ終了します。
稀に(管理者によるデータベース停止コマンドなど)、バックエンドはフロントエンドからの要求なしに切断することがあります。 こうした場合、バックエンドは、接続を閉ざす前に切断理由を通知するエラーまたは警報メッセージの送信を試みます。
他にも、どちらかの側のコアダンプ、通信リンクの消失、メッセージ境界の同期の消失など各種失敗によって終了する状況があります。 フロントエンドかバックエンドいずれかが予期しない接続の中断を検知した場合、後始末を行い終了しなければいけません。 フロントエンドはもし自身が終了を望まない場合、サーバに再交信し新規のバックエンドを立ち上げる選択権を持っています。 解釈できないメッセージ種類を受けとった時、おそらくメッセージ境界の同期が消失したことを示しますので、接続を閉ざすことを勧めます。
通常の終了、異常な終了のどちらの場合でも、開いているトランザクションはすべてコミットされずにロールバックされます。 しかし、フロントエンドがSELECT以外の問い合わせを処理中に切断した場合、バックエンドはおそらく切断に気づく前にその問い合わせを完了させてしまうでしょう。 その問い合わせがトランザクションブロック(BEGIN ... COMMITの並び)外部であった場合、切断に気付く前にその結果はコミットされる可能性があります。
PostgreSQLがSSLサポート付きで構築された場合、フロントエンドとバックエンド間の通信をSSLで暗号化することができます。 攻撃者がセッショントラフィックをキャプチャできるような環境における通信を安全にすることができます。
SSL暗号化接続を初期化するには、フロントエンドはまず、StartupMessageではなくSSLRequestを送信します。 その後サーバはそれぞれSSLの実行を行うか行わないかを示すSかNかを持つ1バイトの応答を返します。 フロントエンドはその応答に満足できなければ、この時点で接続を切断することができます。 Sの後にサーバと間でSSL起動ハンドシェーク(ここではSSLの仕様に関しては説明しません)が行われます。 これが成功した場合、続いて通常のStartupMessageの送信を行います。 この場合、StartupMessageおよびその後のデータはSSLにより暗号化されます。 Nの後に、通常のStartupMessageを送信することで暗号化なしで進みます。
また、フロントエンドはサーバからのSSLRequestに対するErrorMessage応答を取り扱うための用意をすべきです。 これは、PostgreSQLにSSLサポートが追加される前のサーバの場合のみで発生します。 この場合接続を切断しなければなりませんが、フロントエンドはSSL要求無しで新しく接続を開き、処理を進めることもできます。
最初のSSLRequestはCancelRequestメッセージを送信するために開いた接続で使用することもできます。
プロトコル自体には、サーバにSSL暗号化を強制する方法は用意されていませんが、管理者は認証検査の一方法として、暗号化されていないセッションを拒否するようにサーバを設定することができます。