PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

54.1. 概述 #

54.1.1. 消息传递机制概述
54.1.2. 扩展查询协议概述
54.1.3. 格式与格式代码
54.1.4. 协议版本

该协议分为启动阶段和正常操作两个阶段。 在启动阶段,前端打开一个到服务器的连接, 并以让服务器满意的方式认证自己。 (这可能只涉及一条消息,也可能因所用的认证方法而涉及多条消息。) 如果一切顺利,服务器随后会向前端发送状态信息,最后进入正常操作。 除最初的启动请求消息外,协议的这一部分由服务器驱动。

在正常操作期间,前端向后端发送查询和其他命令, 后端送回查询结果和其他响应。有少数情况(例如 NOTIFY) 后端会主动发送未经请求的消息,但会话的这一部分 在大多数时候是由前端的请求驱动的。

会话的终止通常由前端决定,但在某些情况下也可能由后端强制进行。 无论如何,当后端关闭连接时,它会在退出之前回滚任何打开的 (未完成的)事务。

在正常操作中,SQL 命令可以通过两种子协议中的任意一种执行。 在“简单查询”协议中,前端只是发送一个文本形式的查询字符串, 它会被后端解析并立即执行。在“扩展查询”协议中, 对查询的处理被分为多个步骤:解析、绑定参数值和执行。 这带来了灵活性和性能上的收益,代价是额外的复杂性。

正常操作还有用于特殊操作(例如 COPY) 的额外子协议。

54.1.1. 消息传递机制概述 #

所有通信都通过一个消息流进行。消息的第一个字节标识消息类型, 接下来的四个字节说明消息其余部分的长度 (该长度计数包含它自身,但不包含消息类型字节)。 消息的其余内容由消息类型决定。出于历史原因, 客户端发送的第一条消息(启动消息)没有开头的消息类型字节。

为了避免与消息流失去同步,服务器和客户端通常都会在尝试处理消息内容之前 先把整条消息(按字节计数)读入缓冲区。这样, 如果在处理内容时检测到错误,就能轻松恢复。 在极端情况下(例如没有足够的内存来缓冲消息), 接收方可以使用字节计数来确定在恢复读取消息之前要跳过多少输入。

反过来,服务器和客户端都必须注意绝不发送不完整的消息。 常见的做法是在开始发送之前把整条消息编组到缓冲区中。 如果在发送或接收消息的过程中发生通信故障, 唯一明智的响应就是放弃该连接,因为恢复消息边界同步的希望渺茫。

54.1.2. 扩展查询协议概述 #

在扩展查询协议中,SQL 命令的执行被划分为多个步骤。 步骤之间保留的状态由两类对象表示:预备语句和 门户。预备语句表示对一个文本查询字符串 进行解析和语义分析的结果。 预备语句本身还不能执行,因为它可能缺少 参数的具体值。门户表示一条准备好执行的 或已经部分执行的语句,其中所有缺失的参数值都已被填入。 (对于 SELECT 语句, 门户等价于一个打开的游标,但我们选择使用另一个术语, 因为游标不能处理非 SELECT 语句。)

总的执行周期包括一个解析步骤, 它从文本查询字符串创建一条预备语句;一个绑定步骤, 它给定一条预备语句和所需参数的值并据此创建一个门户; 以及一个运行门户查询的执行步骤。 对于返回行的查询(SELECT、SHOW 等), 可以指示执行步骤只抓取有限的行数, 因此可能需要多个执行步骤才能完成整个操作。

后端可以跟踪多条预备语句和多个门户 (但请注意,它们只存在于一个会话之内,从不在会话之间共享)。 现有的预备语句和门户通过它们创建时被赋予的名字来引用。 此外,还存在一个“未命名”的预备语句和门户。 尽管它们的行为在很大程度上与命名对象相同, 但针对它们的操作被优化为适用于只执行一次查询然后丢弃的场景, 而针对命名对象的操作则是以多次使用为预期进行优化的。

54.1.3. 格式与格式代码 #

特定数据类型的数据可能以若干不同的格式传输。 自 PostgreSQL 7.4 起, 唯一支持的格式是“文本”和“二进制”, 但协议为未来的扩展做了准备。 任何值想要的格式由一个格式代码指定。 客户端可以为每个传输的参数值以及查询结果的每一列指定格式代码。 文本的格式代码是零,二进制的格式代码是一, 所有其他格式代码都保留给未来的定义。

值的文本表示就是针对特定数据类型的输入/输出转换函数 产生和接受的任何字符串。在传输表示中,没有结尾的空字符; 如果前端想把接收到的值作为 C 字符串处理, 它必须自行加上一个。 (顺便说一句,文本格式不允许内嵌的空字符。)

整数的二进制表示使用网络字节序(最高有效字节在前)。 对于其他数据类型,请查阅文档或源代码来了解其二进制表示。 请记住,复杂数据类型的二进制表示可能会随服务器版本而变化; 文本格式通常是更具可移植性的选择。

54.1.4. 协议版本 #

当前最新的协议版本是 3.2。不过,为了向后兼容尚不支持版本协商的 旧服务器版本和中间件,libpq 默认仍使用协议版本 3.0。

一台服务器可以支持多个协议版本。最初的启动请求消息 会告诉服务器客户端尝试使用的协议版本。 如果客户端请求的主版本不受服务器支持,连接将被拒绝 (例如,如果客户端请求协议版本 4.0 —— 截至撰写本文时它并不存在, 就会发生这种情况)。如果客户端请求的次版本不受服务器支持 (例如,客户端请求版本 3.2,但服务器只支持 3.0), 服务器既可以拒绝该连接,也可以响应一条 NegotiateProtocolVersion 消息,其中包含它所支持的最高次协议版本。 然后,客户端可以选择使用指定的协议版本继续该连接, 或者中止该连接。

协议协商是在 PostgreSQL 9.3.21 版本中引入的。 更早的版本在客户端请求服务器不支持的次版本时会直接拒绝连接。

Table 54.1 展示了当前支持的 协议版本。

Table 54.1. 协议版本

VersionSupported byDescription
3.2PostgreSQL 18 and later当前最新版本。用于查询取消的秘密密钥 从 4 字节扩大为一个变长字段。BackendKeyData 消息 为此做了相应更改,并且 CancelRequest 消息 被重新定义为带有一个变长的载荷。
3.1-保留。任何 PostgreSQL 版本都没有使用过版本 3.1, 之所以跳过它,是因为流行应用 pgbouncer 的旧版本在协议协商中 存在一个缺陷,使其错误地声称自己支持版本 3.1。
3.0PostgreSQL 7.4 and later 
2.0up to PostgreSQL 13详情请参阅 PostgreSQL 以前版本的文档