第 44章フロントエンド/バックエンドプロトコル

目次
44.1. 概要
44.1.1. メッセージ処理の概要
44.1.2. 拡張問い合わせの概要
44.1.3. 書式と書式コード
44.2. メッセージの流れ
44.2.1. 開始
44.2.2. 簡易問い合わせ
44.2.3. 拡張問い合わせ
44.2.4. 関数呼出し
44.2.5. COPY 操作
44.2.6. 非同期操作
44.2.7. 処理中のリクエストの取り消し
44.2.8. 終了
44.2.9. SSLセッション暗号化
44.3. メッセージのデータ型
44.4. メッセージの書式
44.5. エラーおよび警報メッセージフィールド
44.6. プロトコル2.0からの変更点の要約

PostgreSQLはフロントエンドとバックエンド(クライアントとサーバ)の通信にメッセージベースのプロトコルを使用します。 このプロトコルはTCP/IPやUnixソケットをサポートします。 ポート番号5432は、このプロトコルをサポートするサーバ用のTCPポートとしてIANAで登録されました。 しかし、実際には任意の非特権ポート番号を使用することができます。

この文書はPostgreSQL 7.4以降に実装されたプロトコル3.0バージョンについて記載します。 以前のプロトコルバージョンについての説明は、PostgreSQLの以前のリリースの文書を参照してください。 初めの開始要求メッセージは、サーバに対し、クライアントが使用する予定のプロトコルバージョンを通知します。 その後、サーバは可能であればそのプロトコルに従います。

本プロトコル上に構築されたより高度の機能(たとえば、接続確立時にどのようにlibpqがある特定の環境変数を渡すか)については、他の文書で説明します。

効率的に複数のクライアントにサービスを提供するために、サーバは各クライアント用に新規に"バックエンド"プロセスを起動します。 現在の実装では、サーバに接続が届いたことを検知すると即座に新しい子プロセスが生成されます。 しかし、これはプロトコルに対して透過です。 プロトコルという意味では、"backend""server"という用語は相互交換可能です。同様に"frontend""client"も相互交換可能です。

44.1. 概要

このプロトコルでは、接続開始と通常操作で段階が分かれています。 接続開始段階では、フロントエンドはサーバへの接続を開き、サーバを満足させるように自身を証明します。 (これは使用する認証方法に応じて、単一のメッセージになるかもしれませんし、複数のメッセージになるかもしれません。) すべてうまくいけば、サーバはフロントエンドに状態情報を送信し、最終的に通常操作段階に入ります。 初めの開始要求メッセージを除き、プロトコルのこの部分はサーバによって駆動されます。

通常操作の間、フロントエンドは問い合わせやその他のコマンドをバックエンドに送信し、バックエンドは問い合わせやその他の応答を返送します。 バックエンドから依頼されずにメッセージが送信されるわずかな場合(NOTIFYなど)がありますが、セッションのこの部分のほとんどはフロントエンドの要求によって駆動されます。

セッションの終了は通常フロントエンドが選択することですが、特定の場合はバックエンドによって強制される可能性があります。 どちらの場合でも、バックエンドが接続を閉ざす時、終了前に実行中(不完全な)トランザクションをすべてロールバックします。

通常操作中は、SQLコマンドを2つのサブプロトコルのどちらかを通して実行することができます。 "簡易問い合わせ"プロトコルでは、フロントエンドはテキストで問い合わせ文字列を単に送信し、バックエンドによって解析され、実行されます。 "拡張問い合わせ"プロトコルでは、問い合わせの処理は、解析、パラメータ値の結びつけ、実行という複数の段階に分離されます。 これは、余計な複雑性のコストという欠点と柔軟性と性能についての利点を提供します。

通常操作には、更に、COPYのような特殊な操作向けのサブプロトコルがあります。

44.1.1. メッセージ処理の概要

すべての通信はメッセージストリームを介します。 メッセージの先頭バイトはメッセージ種類を識別するもの、次の4バイトはメッセージの残りの長さを指定するものです。 この長さにはメッセージ種類バイトは含まれませんが、自身は含まれます。) メッセージ内容の残りの部分は、メッセージ種類で決まります。 歴史的な理由のため、一番初めにクライアントから送信されるメッセージ(開始メッセージ)にはメッセージ種類バイトはありません。

メッセージストリームの同期ずれを防ぐために、サーバとクライアントの両方は、通常、メッセージの内容を処理し始める前に、(バイト数を使用して)メッセージ全体をバッファ内に読み込みます。 これにより、その内容を処理する時にエラーが検出された場合に、簡単に復旧することができます。 ごく稀な状況(メッセージをバッファするために十分なメモリがない場合)では、受信側は、バイト数を使用して、メッセージの読みとりを再開する前にどれだけの入力を飛ばすかどうかを決定することができます。

反対に、サーバとクライアントの両方は、不完全なメッセージを決して送信しないように注意しなければなりません。 これは通常、送信する前にメッセージ全体をバッファ内に整理することで行なわれます。 メッセージ境界の同期を復旧できる望みはほとんどありませんので、メッセージの送受信の途中で通信エラーが発生した場合、実用的な唯一の応答は通信を中断することです。

44.1.2. 拡張問い合わせの概要

拡張問い合わせプロトコルでは、SQLコマンドの実行は複数の段階に分割されます。 段階間で保持される状態は、プリペアドステートメントポータルの2種類のオブジェクトで表現されます。 プリペアドステートメントは、解析、意味解析、テキスト問い合わせ文字列の計画作成結果を表現します。 プリペアドステートメントは実行準備が整ったことを必ずしも示しません。 パラメータの特定の値が欠落しているかもしれないからです。 ポータルは、すべてのパラメータ値が設定され、実行準備が整った、あるいは、既に一部実行された文を表現します。 (SELECT文では、ポータルは開いているカーソルと等価です。しかし、カーソルはSELECT以外の文を扱いませんので、ここでは異なる用語を使用するよう選択しました。)

実行サイクル全体は、テキストの問い合わせ文字列からプリペアドステートメントを生成する解析段階、プリペアドステートメントと必要なパラメータ値によりポータルを作成するバインド段階、ポータルの問い合わせを実行する実行段階からなります。 行を返す問い合わせ(SELECTSHOWなど)の場合、操作を完了させるために複数の実行段階が必要とすることができるように、実行段階に限定された行数のみを取り出すよう指示することができます。

バックエンドはプリペアドステートメントとポータルを複数管理することができます。 (しかし、1つのセッション内でのみ存在可能です。複数のセッションで共有することはできません。) 存在するプリペアドステートメントとポータルは、作成時に割り当てられた名前で参照されます。 さらに、"命名されない"プリペアドステートメントとポータルも存在します。 これらは名前付きのオブジェクトとほとんど同じ動きをしますが、問い合わせの実行が1度のみで削除される場合向けに最適化されています。 一方、名前付きオブジェクトの操作は複数回の使用を想定して最適化されています。

44.1.3. 書式と書式コード

特定のデータ型のデータは複数の異なる書式のいずれかで転送される可能性があります。 PostgreSQL 7.4でサポートされる書式は"テキスト""バイナリ"のみですが、プロトコルは将来の拡張用に備えて準備をしています。 任意の値の必要な書式は書式コードで指定されます。 クライアントは、転送されるパラメータ値それぞれに書式コードを指定することも、問い合わせ結果の列それぞれに書式コードを指定することも可能です。 テキストは書式コードゼロ、バイナリは書式コード1です。他の書式コードは将来の定義用に予約されています。

値のテキスト表現は、特定のデータ型の入出力変換関数で生成され、受け付けられる何らかの文字列です。 転送時の表現では、ヌル終端文字はありません。 フロントエンドでC文字列として処理したい場合は、必ず受信した値にヌル終端文字を追加しなければなりません。 (ついでですが、テキスト書式ではヌルを埋め込むことはできません)

整数用のバイナリ表現はネットワークバイト順(先頭に最上位バイト)を使用します。 他のデータ型のバイナリ表現については、文書もしくはソースコードを参照してください。 複雑なデータ型のバイナリ表現はサーバのバージョンによって異なる可能性があることに注意してください。 通常テキスト書式の方がより移植性が高い選択です。