Chapter 42. 前/後端協議

Table of Contents
42.1. 概述
42.1.1. 消息概貌
42.1.2. 擴展查詢概述
42.1.3. 格式和格式代碼
42.2. 消息流
42.2.1. 啟動
42.2.2. 簡單查詢
42.2.3. 擴展查詢
42.2.4. 函數調用
42.2.5. COPY 操作
42.2.6. 異步操作
42.2.7. 取消正在處理的請求
42.2.8. 終止
42.2.9. SSL 會話加密
42.3. 消息資料類型
42.4. 消息格式
42.5. 錯誤和通知消息字串
42.6. 自協議 2.0 以來的變化的概述

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

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

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

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

42.1. 概述

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

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

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

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

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

42.1.1. 消息概貌

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

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

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

42.1.2. 擴展查詢概述

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

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

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

42.1.3. 格式和格式代碼

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

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

整數的二進製資料表現形式採用網絡字元序(高位在前)。對於其它資料類型, 情參考文件或者原始碼獲取其二進製資料表現形式的訊息。請注意,複雜的資料類型的二進制形式可能在不同伺服器版本之間變化; 文本格式通常是最具有移植性的選擇。