Chapter 44. 前/後端協議

Table of Contents
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 以來的變化的概述

Postgres 使用一種基于消息的協議用于前端和後端(服務器和客戶機)之間通訊。 該協議是在 TCP/IP 和 Unix 域套接字上實現的。 端口號 5432 已經在 IANA 注冊為使用這種協議的常用端口,但實際上任何非特權端口號都可以使用。

這份文檔描述了版本 3.0 的協議,在 Postgres 版本 7.4 和以後的版本中實現。 對于以前的協議的描述,請參考以前版本的 PostgreSQL 文檔。 一個服務器可以支持多種協議版本。初始化的啟動信息告訴服務器客戶端可以接受的協議版本,然後服務器則遵守該版本的協議──如果它能做到的話。

在這個協議的基礎上建立的更高級特性(例如,libpq 是如何在建立聯接以後傳遞某種環境變量的)在其他地方描述.

為了可以有效地為多個客戶端提供服務,服務器為每個客戶端派生一個新的"後端"進程。 在目前的實現裡,在檢測到到來的連接請求後,馬上創建一個新的子進程。 不過,這些是對協議透明的。對于協議而言,術語"後端""服務器"是可以互換的; 類似的還有"前端""客戶機"也是可以互換的。

44.1. 概述

協議在啟動和正常操作過程中有不同的階段。 在啟動階段裡,前端打開一個到服務器的連接並且認證自身以滿足服務器。 (這些可能包含一條消息,也可能包含多條消息,根據使用的認證方法而不同。) 如果所有這些事情都運行平穩,那麼服務器就發送狀態信息給前端,並最後進入正常操作。 除了初始化的啟動請求之外,這部分協議是服務器驅動的。

在正常操作中,前端發送查詢和其它命令到後端,然後後端返回查詢結果和其它響應。 有少數幾種情況(比如 NOTIFY)是後端發送主動提供的消息,但這部分的絕大多數情況都是由前端請求驅動的。

會話的終止通常是由前端來選擇的,但是也可以在某些情況下由後端強制執行。 不管那種情況,如果後端關閉連接,那麼他將在退出之前回滾(完成)所有打開的(未完成的)事務。

在正常操作中,SQL 命令可以通過兩個子協議中的任何一個執行。 在"簡單查詢"協議中,前端只是發送一個文本查詢串, 然後後端馬上分析並執行它。在"擴展查詢"協議中, 查詢的處理被分割為多個步驟:分析,參數值綁定,和執行。 這樣就可以提供靈活性和性能的改進,代價是額外的復雜性。

正常操作有用于類似 COPY 這樣的額外的子協議。

44.1.1. 消息概貌

所有通訊都是通過一個消息流進行的。消息的第一個字節標識消息類型, 然後後面跟著的四個字節聲明消息剩下部分的長度(這個長度包括長度域自身,但是不包括消息類型字節)。 剩下的消息內容由消息類型決定。由于歷史原因,客戶端發送的最早的消息(啟動消息)沒有初始的消息類型字節。

為了避免和消息流丟失同步信息,服務器和客戶端通常都是把整個消息讀取到一個緩衝區裡(使用字節計數), 然後才試圖處理其內容。這樣我們在處理內容的過程中,如果發現錯誤,就比較容易恢復。 在非常罕見的情況下(比如說沒有足夠的信息緩衝消息),接收端可以使用字節計數來判斷它在重新讀取信息之前需要忽略多少輸入。

通常,服務器和客戶端都需要注意決不發送一條不完整的消息。 這些通常是通過在發送整條信息之前,在一個緩衝區裡整理整條消息。 如果在發送或者接受一條消息的中間發生了通訊錯誤,那麼唯一合理的反應是放棄連接,因為恢復消息邊界同步的可能性很小。

44.1.2. 擴展查詢概述

在擴展查詢協議中,SQL 命令的執行是分割成多個步驟的。 步驟與步驟之間保存的狀態是由兩類的對象代表的: 準備好的語句(prepared statements)入口(portals)。 一個準備好的語句代表一個文本查詢字串的經過分析,語意解析,以及規劃之後的結果。 一個準備好的語句不一定就是可以執行的,因為它可能還缺乏 參數的值。 一個入口代表一個已經可以執行的或者已經部分執行過的語句,所有參數都已經填充到位了。 (對于SELECT語句,入口等效于一個打開的遊標, 我們使用不同的術語是因為遊標不能處理非SELECT語句。)

完整的執行週期包括一個分析步驟, 它從一個文本的查詢字串裡創建一個準備好的語句; 一個綁定(bind)步驟, 它用一個準備好的語句和任何所需要的參數值創建一個入口;以及一個 執行(execute)步驟,它運行一個入口的查詢。 如果是一個返回數據行的查詢(SELECTSHOW 等), 系統可以告訴執行步驟只抓取有限的一些行,這樣就可能需要多個執行步驟來完成操作。

後端可以跟蹤多個準備好的語句和入口(但是要注意,這些只在一個會話內部存在,從來不能在會話之間共享)。 現存的準備好地語句和入口都是用創建它們的時候賦予的名字引用的。 另外,還存在一個"未命名(unnamed)" 的準備好語句和入口。 盡管它們的行為和命名對象大部分相同,但是它們是針對只執行一次然後就拋棄的查詢進行優化過的, 而在命名對象上的操作是針對多次使用優化的。

44.1.3. 格式和格式代碼

特定數據類型的數據可以用幾種不同的格式中的任意一種來傳遞。 到 PostgreSQL 7.4 的時候,只支持"文本""二進制"兩種格式, 但是協議為未來的擴展提供了的手段。任意值要求的格式是用一個格式代碼聲明的。 客戶端可以為每個傳輸的參數值和查詢結果的每個字段聲明一個格式代碼。 文本的格式代碼是零,二進制的格式代碼是一,所有其它的格式代碼都保留給將來定義。

文本方式的數值是特定數據類型的輸入/輸出轉換函數接受或者生成的數值的字串形式。 在傳輸表現上,字串末尾沒有空字符;如果前端要想把收到的值當作 C 字串處理,那麼必須自己加上一個。 (另外,文本格式不允許嵌入的空。)

整數的二進制表現形式採用網絡字節序(高位在前)。對于其它數據類型, 情參考文檔或者源代碼獲取其二進制表現形式的信息。請注意,復雜的數據類型的二進制形式可能在不同服務器版本之間變化; 文本格式通常是最具有移植性的選擇。