メッセージの流れ

PostgreSQL 8.4.1文書
前のページ | 巻戻し | 第 45章フロントエンド/バックエンドプロトコル | 早送り | 次のページ

# 45.2. メッセージの流れ

本節では、メッセージの流れと各メッセージ種類のセマンティックスを説明します （各メッセージの正確な表現の詳細は項45.4で説明します）。 開始、問い合わせ、関数呼び出し、`COPY`、終了といった接続状態に応じて、複数の異なるサブプロトコルがあります。 また、開始段階の後の任意の時点で発生する可能性がある、非同期操作（通知応答やコマンドのキャンセルを含む）用の特別な準備もあります。

## 45.2.1. 開始

セッションを始めるために、フロントエンドはサーバへの接続を開き、開始メッセージを送信します。 このメッセージには、ユーザ名と接続を希望するデータベース名が含まれます。 これはまた、使用する特定のプロトコルバージョンを識別します （オプションとして、開始メッセージに、実行時パラメータの追加設定を含めることもできます）。 サーバはその後、この情報と設定ファイル（`pg_hba.conf`など）の内容を使用して、接続が仮に受け付けることができるかどうか、（もしあれば）どのような追加認証が必要かを決定します。

サーバはその後、適切な認証要求メッセージを送信します。 フロントエンドはこれに適切な認証応答メッセージ（パスワードなど）で答えなければなりません。 GSSAPIとSSPIを除くすべての認証方式では、多くても１つの要求と１つの応答が存在します。 認証方式の中には、フロントエンドからの応答をまったく必要としないものもあり、その場合、認証要求も発生しません。 GSSAPIとSSPIでは認証を完了するために複数のパケットの交換が必要となるかもしれません。

認証サイクルは、サーバによって接続要求を拒絶する（ErrorResponse）か、あるいはAuthenticationOkを送信することで終わります。

この段階でサーバから送信される可能性があるメッセージを以下に示します。

ErrorResponse

  接続試行が拒絶されました。 サーバはその後即座に接続を閉ざします。

AuthenticationOk

  認証情報の交換が正常に完了しました。

AuthenticationKerberosV5

  フロントエンドはここでサーバとのKerberos V5認証ダイアログ（ここでは説明しません。Kerberos仕様の一部）に参加する必要があります。 これが成功すれば、サーバはAuthenticationOk応答を行います。 失敗すれば、ErrorResponse応答を行います。

AuthenticationCleartextPassword

  フロントエンドはここで平文形式のパスワードを含むPasswordMessageを送信する必要があります。 これが正しいパスワードであればサーバはAuthenticationOk応答を行います。 さもなくば、ErrorResponse応答を行います。

AuthenticationMD5Password

  フロントエンドはここでAuthenticationMD5Passwordメッセージで指定された4文字をソルトに使用するMD5で暗号化されたパスワードを含むPasswordMessageを送信する必要があります。 これが正しいパスワードであればサーバはAuthenticationOk応答を行います。 さもなくば、ErrorResponse応答を行います。

AuthenticationSCMCredential

  この応答はSCM資格証明メッセージをサポートするプラットフォーム上のローカルなUnixドメイン接続でのみあり得ます。 フロントエンドはSCM資格証明メッセージを発行し、その後単一のデータバイトを送信する必要があります （データバイトの内容には意味はありません。 これはサーバが資格証明メッセージの受信にどれだけ待機すればよいのかを確実にするためだけに使用されます）。 資格証明が受け付け可能であればサーバはAuthenticationOk応答を行います。 さもなくば、ErrorResponse応答を行います。

AuthenticationGSS

  ここでフロントエンドはGSSAPIの調停を開始しなければなりません。 これに対する応答におけるGSSAPIデータストリームの最初の部分で、フロントエンドはPasswordMessageを送信します。 さらにメッセージが必要となる場合、サーバはAuthenticationGSSContinueで応答します。

AuthenticationSSPI

  ここでフロントエンドはSSPI調停を開始しなければなりません。 これに対する応答におけるSSPIデータストリームの最初の部分で、フロントエンドはPasswordMessageを送信します。 さらにメッセージが必要となる場合、サーバはAuthenticationGSSContinueで応答します。

AuthenticationGSSContinue

  このメッセージには、GSSAPIまたはSSPI調停の直前の段階（AuthenticationGSS、AuthenticationSSPIまたは前回のAuthenticationGSSContinue）についての応答データが含まれます。 このメッセージ内のGSSAPIまたはSSPIデータが、認証を完了させるためにはより多くのデータが必要であることを示している場合、フロントエンドは他のPasswordMessageとしてデータを送信しなければなりません。 このメッセージでGSSAPIまたはSSPI認証が完了すれば、次にサーバはAuthenticationOkを送信して認証が成功したことを示すか、あるいはErrorResponseを送信して失敗したことを示します。

フロントエンドが、サーバが要求した認証方式をサポートしていない場合、フロントエンドは即座に接続を閉ざします。

AuthenticationOkを受け取った後、フロントエンドはさらにサーバからのメッセージを待機する必要があります。 この段階で、バックエンドプロセスが起動し、このフロントエンドは単なる興味を持った傍観者でしかありません。 開始試行が失敗（ErrorResponse）する可能性がまだありますが、通常、バックエンドは何らかのParameterStatusメッセージ、BackendKeyData、最後にReadyForQueryを送信します。

この段階の期間中、バックエンドは開始メッセージで与えられた任意の実行時パラメータの追加設定を適用しようとします。 成功した場合は、これらの値はセッションのデフォルトになります。 エラーが発生した場合はErrorResponseを行い、終了します。

この段階でバックエンドから送信される可能性があるメッセージを以下に示します。

BackendKeyData

  このメッセージは、フロントエンドがキャンセル要求を後で送信できるようにしたい場合に保存しなければならない、秘密キーデータを提供します。 フロントエンドはこのメッセージに応答すべきではありません。 ReadyForQueryメッセージの監視を続けるべきです。

ParameterStatus

  このメッセージは、フロントエンドに現在（初期）のclient_encodingやDateStyleなどのバックエンドパラメータの設定情報を通知します。 フロントエンドはこのメッセージを無視しても、将来の使用に備えてその設定を記録しても構いません。 詳細は項45.2.6を参照してください。 フロントエンドはこのメッセージに応答すべきではありません。 ReadyForQueryメッセージの監視を続けるべきです。

ReadyForQuery

  開始処理が完了しました。 フロントエンドはここでコマンドを発行することができます。

ErrorResponse

  開始処理が失敗しました。 接続はこのメッセージの送信後に閉ざされます。

NoticeResponse

  警告メッセージが発行されました。 フロントエンドはこのメッセージを表示し、ReadyForQueryもしくはErrorResponseメッセージの監視を続けるべきです。

ReadyForQueryメッセージは各コマンドサイクルの後にバックエンドが発行するものと同じものです。 フロントエンドのコーディングにおいて必要であれば、ReadyForQueryをコマンドサイクルの開始とみなしても構いませんし、ReadyForQueryを開始段階とその後の各コマンドサイクルの終端とみなしても構いません。

## 45.2.2. 簡易問い合わせ

フロントエンドがQueryメッセージをバックエンドに送信することで、簡易問い合わせサイクルが初期化されます。 このメッセージには、テキスト文字列で表現されたSQLコマンド（またはコマンド）が含まれます。 その後バックエンドは、問い合わせコマンド文字列の内容に応じた1つ以上の応答を送信します。 ReadyForQueryは、新しいコマンドを安全に送信できることをフロントエンドに伝えます （実際には、フロントエンドが他のコマンドを発行する前にReadyForQueryを待機することは不要です。 しかし、フロントエンドは、前のコマンドが失敗し、発行済みの後のコマンドが成功した場合に何が起きるかを了解する責任を持たなければなりません）。

バックエンドから送信される可能性がある応答メッセージを以下に示します。

CommandComplete

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

CopyInResponse

  バックエンドがフロントエンドからのデータをテーブルにコピーする準備ができました。 項45.2.5を参照してください。

CopyOutResponse

  バックエンドがデータをテーブルからフロントエンドにコピーする準備ができました。 項45.2.5を参照してください。

RowDescription

  応答として返す行が`SELECT`や`FETCH`などの問い合わせの結果であることを通知します。 このメッセージには、行の列レイアウトに関する説明が含まれます。 このメッセージの後に、フロントエンドに各行を返すためのDataRowメッセージが続きます。

DataRow

  `SELECT`や`FETCH`などで返される行の集合の1つです。

EmptyQueryResponse

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

ErrorResponse

  エラーが起こりました。

ReadyForQuery

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

NoticeResponse

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

`SELECT`問い合わせ（あるいは、`EXPLAIN`や`SHOW`などの行集合を返す他の問い合わせ）に対する応答は、通常、RowDescription、0個以上のDataRowメッセージ、その後にCommandCompleteから構成されます。 フロントエンドへの`COPY`もしくはフロントエンドからの`COPY`は項45.2.5で説明する特別なプロトコルを呼び出します。 他の種類の問い合わせは通常CommandCompleteメッセージのみを生成します。

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

完全に空の（空白文字以外の文字がない）問い合わせ文字列を受け取った場合、その応答は、EmptyQueryResponse、続いて、ReadyForQueryとなります。

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

簡易問い合わせモードでは、受信する値の書式は常にテキストです。 ただし、与えられたコマンドが`BINARY`オプション付きで宣言されたカーソルからの`FETCH`であった場合は例外です。 この場合は、受信する値はバイナリ書式になります。 RowDescriptionメッセージ内で与えられる書式コードは、どの書式が使用されているかを通知します。

フロントエンドは他の種類のメッセージの受信を待機している時は常にErrorResponseとNoticeResponseメッセージを受け取る準備ができていなければなりません。 また、外部イベントのためにバックエンドが生成する可能性があるメッセージの扱いについて項45.2.6を参照してください。

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

## 45.2.3. 拡張問い合わせ

拡張問い合わせプロトコルは、上述の簡易問い合わせプロトコルを複数段階に分解します。 予備段階の結果は複数回再利用できますので、効率が上がります。 さらに、問い合わせ文字列に直接埋め込むのではなく、データ値をパラメータとして分離して提供できる機能など、利用できる追加機能があります。

拡張プロトコルでは、フロントエンドはまず、テキストの問い合わせ文字列とオプションとしてパラメータプレースホルダのデータ型情報やプリペアド文のオブジェクトの宛先名（空文字列は無名のプリペアド文を選択）を含む、Parseメッセージを送信します。 この応答はParseCompleteまたはErrorResponseです。 パラメータデータ型はそのOIDで指定することができます。 指定がなければ、パーサは型指定のないリテラル文字列定数に対する方法と同じ方法でデータ型を推定します。

> 注意: パラメータデータ型をゼロと設定する、または、問い合わせ内で使用されているパラメータ記号（`$``n`）の数より少なくパラメータ型のOIDの配列を作成することで指定しないまま残すことができます。 他にも、パラメータの型を`void`（つまり`void`仮想型のOID）と指定するという特別な場合があります。 これは、 パラメータ記号を、実際のOUTパラメータである関数パラメータとして使用することができることを意味します。 通常では、`void`パラメータが使用される文脈はありませんが、関数パラメータリストにこうしたパラメータ記号があると、実質的には無視されます。 例えば、`$3`と`$4`が`void`型を持つと指定された場合、`foo($1,$2,$3,$4)`といった関数呼び出しは、2つのINパラメータ、2つのOUTパラメータを持つ関数に一致します。

> 注意: Parseメッセージ内の問い合わせ文字列には、複数のSQL文を含めることはできません。 さもなくば、構文エラーが報告されます。 この制限は簡易問い合わせプロトコルにはありませんが、複数のコマンドを持つプリペアド文やポータルを許すと、プロトコルが複雑になり過ぎるため、拡張プロトコルではこの制限があります。

作成に成功すると、名前付きプリペアド文オブジェクトは明示的に破棄されない限り現在のセッションが終わるまで残ります。 無名のプリペアド文オブジェクトは、次に無名のプリペアド文を宛先に指定したParse文が発行されるまでの間のみに残ります （単なるQueryメッセージでも無名のプリペアド文オブジェクトは破壊されることに注意してください）。 名前付きプリペアド文は、Parseメッセージで再定義する前に明示的に閉じなければなりません。 しかし、これは無名のプリペアド文では必要ありません。 名前付きプリペアド文はまた、SQLコマンドレベルで`PREPARE`と`EXECUTE`を使用して作成しアクセスすることができます。

プリペアド文が存在すると、Bindメッセージを使用してそれを実行可能状態にすることができます。 Bindメッセージは、元となるプリペアド文（空文字列は無名のプリペアド文を表します）、宛先となるポータル（空文字列は無名ポータルを表します）、およびプリペアド文内のパラメータプレースホルダに使用する値を与えます。 与えられたパラメータ集合はプリペアド文で必要とするものと一致しなければなりません。 （Parseメッセージ内で`void`パラメータを1つでも宣言した場合、BindメッセージではそれらにはNULLを渡します。） また、Bindは問い合わせで返されるデータに使用する書式を指定します。 書式は全体に対して指定することも、列単位で指定することも可能です。 応答はBindCompleteもしくはErrorResponseです。

> 注意: テキスト出力とバイナリ出力との選択は、含まれるSQLコマンドに関係なく、Bindで与えられた書式コードで決定されます。 拡張問い合わせプロトコルを使用する場合、カーソル宣言の`BINARY`属性は役に立ちません。

名前付きプリペアド文オブジェクト用の問い合わせ計画はParseメッセージが処理された時に作成されます。 異なるパラメータで問い合わせが繰り返し実行される場合、単一のパラメータ化された問い合わせを持つParseメッセージを送信し、その後に複数のBindメッセージとExecuteメッセージを送信することは有利かもしれません。 これはまた、問い合わせを実行する度に計画を再作成することを防ぎます。

無名のプリペアド文は、Parseメッセージがパラメータを持たない場合は同様に、Parse処理中に計画が作成されます。 しかし、パラメータがあると、問い合わせ計画の作成はBind処理の間に起こります。 これにより、プランナは、問い合わせ計画の作成時にBindメッセージで提供されたパラメータの実際の値を使用することができるようになります。

> 注意: パラメータ化された問い合わせにより生成される問い合わせ計画は、実際のパラメータが埋め込まれた、等価な問い合わせから生成される問い合わせ計画よりも非効率的になるかもしれません。 問い合わせプランナは、名前付きプリペアド文として割り当てられたパラメータ化問い合わせの計画を作成する時に、実際のパラメータ値に基づいた決定（例えばインデックスの選択性）を行うことができません。 実際のパラメータ値がわかるようになるまで計画が生成されませんので、このペナルティは無名の文を使用する場合には発生しません。 問い合わせが同じであっても、こうした計画作成のコストはBind毎に発生します。

作成に成功すると、名前付きポータルオブジェクトは明示的に破棄されない限り現在のセッションが終わるまで残ります。 無名ポータルは、トランザクションの終わり、もしくは、次に無名ポータルを宛先に指定したParse文が発行されるまでの間のみに残ります （単なるQueryメッセージでも無名ポータルは破壊されることに注意してください）。 名前付きポータルは、Bindメッセージで再定義する前に明示的に閉じなければなりません。 しかし、これは無名ポータルでは必要ありません。 名前付きポータルはまた、SQLコマンドレベルで`DECLARE CURSOR`と`FETCH`を使用して作成しアクセスすることができます。

ポータルが存在すると、Executeメッセージを使用してそれを実行することができます。 Executeメッセージは、ポータル名（空文字列は無名ポータルを表します）と結果行の最大数（ゼロは"fetch all rows"を意味します）を指定します。 結果行数は、ポータルが含むコマンドが行集合を返す場合のみ意味があります。 その他の場合では、コマンドは終わりまで実行され、行数は無視されます。 Executeで起こり得る応答は、ExecuteではReadyForQueryやRowDescriptionが発行されない点を除き、上述の簡易問い合わせプロトコル経由で発行された問い合わせの場合と同じです。

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メッセージが返されない点があります。

## 45.2.4. 関数呼び出し

関数呼び出しサブプロトコルにより、クライアントはデータベースの`pg_proc`システムカタログに存在する任意の関数を直接呼び出す要求を行うことができます。 クライアントはその関数を実行する権限を持たなければなりません。

> 注意: 関数呼び出しサブプロトコルは、おそらく新規のコードでは使用すべきではない、古い機能です。 同様の結果は、`SELECT function($1, ...)`を行うプリペアド文を設定することで得ることができます。 そして、この関数呼び出しサイクルをBind/Executeで置き換えることができます。

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

バックエンドから送信される可能性がある応答メッセージを以下に示します。

ErrorResponse

  エラーが起こりました。

FunctionCallResponse

  関数呼び出しが完了し、結果がメッセージ内に返されました （関数呼び出しプロトコルは単一のスカラ結果のみを扱うことができます。行型や結果集合を扱うことはできません）。

ReadyForQuery

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

NoticeResponse

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

## 45.2.5. COPY操作

`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の受信をコピーアウトモードの終了として扱うべきです。

NoticeResponseおよびParameterStatusメッセージがCopyDataメッセージ間に散在することがあります。 フロントエンドはこのような場合も扱わなければなりません。 また、他の種類の非同期メッセージ（項45.2.6を参照）も同様に準備すべきです。 さもなくば、CopyDataまたはCopyDone以外の種類のメッセージがコピーアウトモードの終了として扱われてしまう可能性があります。

CopyInResponseとCopyOutResponseメッセージには、フロントエンドに1行当たりの列数と各列で使用する書式コードを通知するためのフィールドが含まれています （現在の実装では、`COPY`操作で与えられる全ての列は同一の書式を使用します。 しかし、メッセージの設計においては、これを前提としていません）。

## 45.2.6. 非同期操作

バックエンドが、フロントエンドのコマンドストリームで特に依頼されていないメッセージを送信する場合が複数あります。 フロントエンドは、問い合わせ作業を行っていない時であっても常に、これらのメッセージを扱う準備をしなければなりません。 少なくとも、問い合わせの応答の読み込みを始める前にこれらを検査すべきです。

外部の活動によって、NoticeResponseメッセージを生成することが可能です。 例えば、データベース管理者が"高速"データベース停止コマンドを実行した場合、バックエンドは接続を閉ざす前にこれを通知するためにNoticeResponseを送信します。 したがって、たとえ接続が名のみの待機状態であったとしても、フロントエンドは常にNoticeResponseメッセージを受け付け、表示する準備をすべきです。

ParameterStatusメッセージは、任意のパラメータの実際の値が変更され、それをバックエンドがフロントエンドに通知するべきであるとみなした場合は常に生成されます。 ほとんどの場合、これはフロントエンドによる`SET` SQLコマンド実行に対する応答の中で起こります。 これは実質的には同期していますが、管理者が設定ファイルを変更し、SIGHUPシグナルをサーバに送った場合にも、パラメータ状態の変更が発生することがあります。 また、`SET`コマンドがロールバックされた場合、現在の有効値を報告するために適切なParameterStatusメッセージが生成されます。

現時点では、ParameterStatusを生成するパラメータ群は固定されています。 それらは`server_version`、`server_encoding`、`client_encoding`、`is_superuser`、`session_authorization`、`DateStyle`、`IntervalStyle`、`TimeZone`、`integer_datetimes`、および`standard_conforming_strings`です。（8.0より前までのリリースでは、`server_encoding`、`TimeZone`、および`integer_datetimes`は送信されませんでした。8.1より前までのリリースでは、`standard_conforming_strings`は送信されませんでした。8.4より前のリリースでは、`IntervalStyle`は送信されませんでした。） `server_version`、`server_encoding`、および`integer_datetimes`は仮想的なパラメータであり、起動後に変更することができません。 これは今後変更される、あるいは設定変更可能になる可能性があります。 したがって、フロントエンドは解釈しないParameterStatusを単に無視すべきです。

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

> 注意: 現在、NotificationResponseをトランザクションの外部でのみ送信することができます。 このため、これはコマンド応答の流れの途中では起こりませんが、ReadyForQueryの直前に発生する可能性があります。 しかし、これを前提にフロントエンドのロジックを設計することは避けてください。 プロトコル内の任意の時点でNotificationResponseを受け付けられるようにすることを勧めます。

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

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

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

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

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

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

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

## 45.2.8. 終了

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

稀に（管理者によるデータベース停止コマンドなど）、バックエンドはフロントエンドからの要求なしに切断することがあります。 こうした場合、バックエンドは、接続を閉ざす前に切断理由を通知するエラーまたは警報メッセージの送信を試みます。

他にも、どちらかの側のコアダンプ、通信リンクの消失、メッセージ境界の同期の消失など各種失敗によって終了する状況があります。 フロントエンドかバックエンドいずれかが予期しない接続の中断を検知した場合、後始末を行い終了しなければいけません。 フロントエンドはもし自身が終了を望まない場合、サーバに再交信し新規のバックエンドを立ち上げる選択権を持っています。 解釈できないメッセージ種類を受け取った時、おそらくメッセージ境界の同期が消失したことを示しますので、接続を閉ざすことを勧めます。

通常の終了、異常な終了のどちらの場合でも、開いているトランザクションは全てコミットされずにロールバックされます。 しかし、フロントエンドが`SELECT`以外の問い合わせを処理中に切断した場合、バックエンドはおそらく切断に気付く前にその問い合わせを完了させてしまうでしょう。 その問い合わせがトランザクションブロック（`BEGIN` ... `COMMIT`の並び）外部であった場合、切断に気付く前にその結果はコミットされる可能性があります。

## 45.2.9. SSLセッション暗号化

PostgreSQLがSSLサポート付きで構築された場合、フロントエンドとバックエンド間の通信をSSLで暗号化することができます。 攻撃者がセッショントラフィックをキャプチャできるような環境における通信を安全にすることができます。 SSLを使用したPostgreSQLセッションの暗号化に関する詳細は項17.8を参照してください。

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

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

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

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

前のページ | ホーム | 次のページ
概要 | 上に戻る | メッセージのデータ型