他のバージョンの文書 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

4.2. メッセージの流れ

ここではメッセージの流れに付いて記載します。接続の状況によって4 種類の流れ、、つまり、開始、問い合わせ、関数呼び出し、終了、があります。また、開始フェーズ以降の任意の時点で発生し得る通知回答と命令取り消しには、特別な規定が存在します。

4.2.1. 開始

始めにフロントエンドはStartupPacketを送ります。サーバはこの情報とpg_hba.confファイルの内容から、フロントエンドが使用すべき認証方法を決定します。その後、以下のメッセージのどれか1つを返します。

ErrorResponse

この後すぐサーバは接続を切断します。

AuthenticationOk

認証情報の交換が終了しました。

AuthenticationKerberosV4

この後フロントエンドはサーバとKerberos V4の認証手続き(ここではKerberosの仕様については説明しません)を開始しなければいけません。成功すると、サーバはAuthenticationOkを返します。失敗した場合はErrorResponseを返します。

AuthenticationKerberosV5

この後フロントエンドはサーバとKerberos V5の認証手続き(ここではKerberosの仕様については説明しません)を開始しなければいけません。成功すると、サーバはAuthenticationOkを返します。失敗した場合はErrorResponseを返します。

AuthenticationCleartextPassword

この後フロントエンドは平文のパスワードを含んだPasswordPacket を送出しなければいけません。もしこのパスワードが正しければ、サーバはAuthenticationOkを返します。失敗した場合はErrorResponseを返します。

AuthenticationCryptPassword

この後フロントエンドは、AuthenticationCryptPasswordパケット内部で指定した2文字のソルトを使用したcrypt(3)で、暗号化したパスワードを含んだPasswordPacketを送出しなければいけません。もしこのパスワードが正しければ、サーバはAuthenticationOkを返します。失敗した場合はErrorResponseを返します。

AuthenticationMD5Password

この後フロントエンドは、AuthenticationMD5Passwordパケット内部で指定した4文字のソルトを使用したMD5で、暗号化したパスワードを含んだPasswordPacketを送出しなければいけません。もしこのパスワードが正しければ、サーバはAuthenticationOkを返します。失敗した場合はErrorResponseを返します。

AuthenticationSCMCredential

この方式は、SCM資格証明メッセージをサポートするプラットフォームでのローカルなUnixドメイン接続の場合でのみ使用することができます。フロントエンドはSCM 資格証明メッセージを発行し、その後1つのデータバイトを送信しなければなりません。(データバイトの内容には意味がありません。これは資格証明メッセージの受信待機時間を確実にするためだけに使用されます。)資格証明が受け付け可能なものであれば、サーバはAuthenticationOkを返します。さもなくばErrorResponseを返します。

サーバが要求した認証方式をフロントエンドがサポートしていない場合、フロントエンドはすぐに接続を切断しなければなりません。

AuthenticationOkを受け取った後、フロントエンドはその後に続くサーバからのメッセージを待機しなければなりません。この段階でバックエンドが送出するメッセージには以下のものがあります。

BackendKeyData

これは、後にフロントエンドが取り消し要求を発行できるようにするために、保存しておくべき秘密鍵データを提供します。フロントエンドはこのメッセージに応答してはいけませんが、ReadyForQueryメッセージの受信を待機し続ける必要があります。

ReadyForQuery

起動が成功しました。フロントエンドは問い合わせ、または関数呼び出しメッセージを送ることができます。

ErrorResponse

起動に失敗しました。このメッセージ送出後、接続は切断されます。

NoticeResponse

警告メッセージが出されました。フロントエンドはこのメッセージを表示しなくてはいけませんが、引続きReadyForQueryまたはErrorResponseの受信を待機し続けます。

ReadyForQueryメッセージは各問い合わせサイクルの後にバックエンドが出すものと同じものです。フロントエンドのコーディングにおいて必要であれば、ReadyForQueryを問い合わせサイクルの開始とみなしてもかまいません(そしてその場合はBackendKeyDataにより開始フェーズの正常終了を意味します)し、開始フェーズと各問い合わせサイクルの終了とみなしてもよいでしょう。

4.2.2. 問い合わせ

1つの問い合わせサイクルはフロントエンドがバックエンドに問い合わせメッセージを送ることで起動されます。そこでバックエンドは問い合わせ命令の文字列の内容に基づいて1つまたは複数の回答メッセージを送り、最終的にReadyForQuery回答メッセージを送出します。ReadyForQueryはフロントエンドに確実に新規の問い合わせまたは関数呼び出しを行ってもよいことを伝えます。

バックエンドから送られるメッセージとしては以下のものがあります。

CompletedResponse

SQLコマンドが正常に終了しました。

CopyInResponse

バックエンドがフロントエンドからのデータをテーブルにコピーする準備ができました。フロントエンドはここでCopyDataRowsメッセージを送出しなければいけません。その後、バックエンドはCOPYというタグを付けたCompletedResponseメッセージを返します。

CopyOutResponse

バックエンドがデータをテーブルからフロントエンドにコピーする準備ができました。バックエンドはここでCopyDataRowsメッセージに引き続き、COPYという文字列のタグを付けたCompletedResponseメッセージを返します。

CursorResponse

SELECT,FETCH, INSERT,UPDATE, DELETE 問い合わせに対する応答の始まりです。 FETCH の場合、対象としたカーソルの名前がこのメッセージ内に含まれます。その他の場合は、このメッセージは常に "blank" カーソルと報告します。

RowDescription

これは、応答として返す行がSELECT もしくは FETCH 問い合わせの結果であることを意味します。このメッセージには、行のレイアウトに関する説明が含まれます。このメッセージの後、AsciiRowまたはBinaryRow(バイナリカーソルを指定していたかどうかに依存します)メッセージを送出することで、フロントエンドに各行が返されます。

EmptyQueryResponse

空の問い合わせ文字列が検知されました。

ErrorResponse

エラーが発生しました。

ReadyForQuery

問い合わせ文字列の処理が終了しました。問い合わせ文字列は複数のSQLコマンドが含まれる場合があるため、このことを通知するために分離したメッセージが送出されます(CompletedResponse は文字列全体ではなく、1つのSQLコマンドの終了を意味します)。ReadyForQuery は処理が成功しても、エラーとなっても常に送出されます。

NoticeResponse

問い合わせに関して警告メッセージが出されました。 警告メッセージは他の応答に対する追加のメッセージです。従って、バックエンドはそのコマンドの処理を続行します。

SELECT または FETCH 問い合わせに対する応答の構成は、通常、CursorResponse、RowDescription、0個以上の AsciiRow または BinaryRowメッセージ、最後に CompletedResponse メッセージ となります。INSERTUPDATEおよび DELETE 問い合わせでは、CursorResponse、引き続いて、CompletedResponse メッセージが生成されます。フロントエンドとの COPY to または COPY from の場合は、上述の特殊なプロトコルが呼び出されます。他の種類の問い合わせは、すべて通常、CompletedResponse のみが生成されます。

問い合わせ文字列には(セミコロンで区切られた)複数の問い合わせが含まれることがありますので、バックエンドが問い合わせ文字列の処理を完了する前に、上の応答シーケンスが複数発生する可能性があります。ReadyForQuery は、文字列全体が処理され、バックエンドが新しい問い合わせ文字列を受け付ける準備が整った時点で発行されます。

完全に空の(空白文字以外の文字がない)問い合わせ文字列を受け取った場合、その応答は、EmptyQueryResponse、続いて、ReadyForQuery となります(これを特別に区別しなければならない理由は歴史的なものです)。

エラーが発生した場合、ErrorResponse、続いて、ReadyForQuery が発行されます。その問い合わせ文字列に対する以降の処理は(複数の問い合わせが残っていたとしても)全て、ErrorResponseによって中断されます。これは、個々の問い合わせで生成されるメッセージのシーケンスの途中で発生する可能性があることに注意して下さい。

フロントエンドは、他の何らかのメッセージの受信を待機している時は常に、ErrorResponse および NoticeResponse メッセージを受け取れるよう準備をしなければなりません。

実際、NoticeResponse は、フロントエンドが他のメッセージの受信を待機していない時、つまり、バックエンドが名目上待機している時でさえ、発生することがあります(特に、バックエンドがその親プロセスによって終了するようなコマンドを受け付けることがあります。その場合、接続が切断される前にNoticeResponseが送出されます)。フロントエンドで、新しいコマンドを発行する前に、こういった非同期の警告メッセージを検査することを推奨します。

また、フロントエンドが何らかの LISTEN を発行した場合、常に NotificationResponse を受け取る準備を行なわなければなりません。

メッセージの正しい並びを前提としてコーディングするのではなく、任意のメッセージ種類を、そのメッセージが意味を持つ任意の時点で受け付ける状態マシン形式でフロントエンドのコーディングを行なうことを推奨します。

4.2.3. 関数呼び出し

関数呼び出しサイクルはフロントエンドがFunctionCallメッセージをバックエンドに送ることで起動されます。バックエンドは1つまたは複数の応答メッセージを関数呼び出しの結果に基づいて送り、最終的にReadyForQueryメッセージを送出します。ReadyForQueryはフロントエンドに対し新規の問い合わせまたはは関数呼び出しを行っても安全確実であることを通知します。

バックエンドからの応答メッセージとして以下があります。

ErrorResponse

エラーが起こりました。

FunctionResultResponse

関数呼び出しが処理され結果が返されました。

FunctionVoidResponse

関数呼び出しは処理されましたが結果は返されませんでした。

ReadyForQuery

関数呼び出しの処理が終了しました。処理が成功またはエラーで終了したかどうかにかかわらずReadyForQueryは常に送出されます。

NoticeResponse

関数呼び出しに関して警告メッセージが出されました。 警告メッセージは他の応答に対する追加のメッセージです。従って、バックエンドはそのコマンドの処理を続行します。

フロントエンドは他の種類のメッセージの受信を待機している時は常に ErrorResponseとNoticeResponseメッセージを受け取る準備ができていなければ なりません。同時にLISTEN コマンドを送出した場合、常時 NotificationResponseメッセージを受け取れる準備ができていなくてはいけません。下記を参照してください。

4.2.4. 通知への応答

フロントエンドがLISTEN コマンドを発行した場合、同じ通知名に対しNOTIFY コマンドが実行された時にバックエンドはNofificationResponseメッセージ(NoticeResponseと間違えないように!)を送出します。

(起動後において)通知への応答は、他のバックエンドメッセージの処理シーケンスの途中でない限り、任意の時点で発生します。したがって、フロントエンドは他のメッセージを待機している時は常にNotificationResponseメッセージを受け取れる準備ができていなければいけません。実際、問い合わせに関与していないときでもNotificationResponseを処理することができなければいけません。

NotificationResponse

事前に実行されたLISTENコマンドの名前に対しNOTIFY(l)命令が実行されました。通知は任意の時点で送出される可能性があります。

listenコマンドとnotifyコマンドで使用される名前は、SQLデータベース内のリレーション(テーブル)の名前と関連付ける必要がない事を指摘しておいたほうがよいでしょう。通知名は単に勝手に選択できる条件の名称です。

4.2.5. 処理中のリクエストの取り消し

問い合わせの処理中に、フロントエンドは問い合わせを取り消すことができます。取り消し要求は、効率を高めるために、接続を開いたバックエンドに対して直接送信されません。その問い合わせを処理中のバックエンドが、フロントエンドからの新しい入力があるかどうかを定期的に確認することは好ましくありません。取り消し要求はたいていの場合、頻繁には起こらないので、通常の状態においての負担を避けるため、多少扱いにくくなっています。

取り消し要求を出す場合、フロントエンドは通常の新規接続のときに送出されるStartupPacketメッセージではなくCancelRequestメッセージをサーバに送り、新規接続を開始します。サーバはこの要求を処理し、接続を切断します。セキュリティ上の理由から、取り消し要求メッセージに対し直接の回答はありません。

CancelRequestメッセージは、接続開始段階でフロントエンドに送られたのと同一の鍵データ(PIDと秘密鍵)を含んでいない場合は無視されます。現在バックエンドが実行中の処理に対するPIDと秘密鍵が要求と一致した場合、その現在の問い合わせ処理は中断されます。(現状では、これは、その問い合わせを処理しているバックエンドプロセスに対し特別な信号を送信することで実装されています。)

この取り消し信号は何の効果も生まないことがあります。たとえば、バックエンドが問い合わせの処理を完了した後に届いた場合、効果がありません。もし取り消し処理が有効であれば、エラーメッセージとともに、現在の命令は終了されます。

セキュリティと効率の理由による上述の実装の結果、フロントエンドは取り消し要求が成功したかどうかを直接判断することはできません。フロントエンドはバックエンドからの問い合わせの回答を待ち続けなければいけません。取り消しを要求することは単に現在の問い合わせを早めに終わらせ、成功ではなくエラーメッセージを出して不成功とする可能性を多少高める程度のものです。

取り消し要求は、通常のフロントエンドとバックエンドの通信接続を通してではなく新規のサーバとの接続に送られるため、取り消される問い合わせを実行したフロントエンドだけでなく、任意のプロセスによっても出される可能性があります。このことはマルチプロセスアプリケーションを作るに当たって柔軟性を提供します。同時に、承認されていない者が問い合わせを取り消そうとするといったセキュリティ上のリスクも持ち込みます。このセキュリティ上のリスクは、取り消し要求内に動的に生成される秘密キーを供給することを必須とすることで回避されます。

4.2.6. 終了

通常の洗練された終了手順はフロントエンドがTerminateメッセージを出し、すぐに接続を閉じることです。このメッセージを受け取るとすぐにバックエンドは接続を閉じ終了します。

洗練されていない終了はどちらかの側のソフトウェアの失敗(たとえばコアダンプ)によって起こることがあります。フロントエンドかバックエンドいずれかが予期しない接続の中断を検知した場合、後始末を行い終了しなければいけません。フロントエンドはもし自身が終了を望まない場合、postmasterに再交信し新規のバックエンドを立ち上げる選択権を持っています。

正常終了、異常終了のどちらの場合でも、開いているトランザクションはすべてコミットされず、ロールバックされます。しかし、問い合わせの処理中にフロントエンドが接続を切断した場合、バックエンドはその切断に気づく前におそらくその問い合わせを完了させてしまうことに注意しなければなりません。その問い合わせがトランザクションブロック(BEGIN ... COMMIT の間)の外部にあった場合、その結果は切断が検出される前にコミットされます。

4.2.7. SSL セッション暗号化

PostgreSQL の最近のリリースでは、SSLを使用して、フロントエンドとバックエンド間の通信を暗号化することができます。攻撃者がセッショントラフィックをキャプチャできるような環境における通信を安全にすることができます。

SSl 暗号化接続を初期化するには、フロントエンドはまず、StartupPacket ではなくSSLRequestを送信します。その後サーバはそれぞれ SSl の実行を行うか行わないかを示すYN かを持つ1バイトの応答を返します。フロントエンドはその応答に満足できなければ、この時点で接続を切断することができます。Y の後にサーバ間で SSL 起動ハンドシェークが行われます(ここではSSLの仕様に関しては説明しません)。これが成功した場合、通常の StartupPacket の送信を行います。この場合、StartupPacket およびその後のデータは SSL により暗号化されます。N の後に、通常の StartupPacket を送信することで暗号化なしで進みます。

また、フロントエンドはサーバからのSSLRequestに対するErrorMessageを取り扱うための用意をしなければなりません。これは、PostgreSQLにSSLサポートが追加される前のサーバの場合のみで発生します。この場合接続を切断しなければなりませんが、フロントエンドはSSL要求無しで新しく接続を開き、処理を進めることもできます。

最初のSSLRequest は CancelRequest メッセージを送信するために開いた接続で使用することもできます。

プロトコル自体には、サーバにSSL暗号化を強制する方法は用意されていませんが、管理者は認証検査の一方法として、暗号化されていないセッションを拒否するようにサーバを設定することができます。