↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16
开发中的版本: 19 / 20devel
开发快照。 PostgreSQL 20devel 尚未正式发布,内容仍可能变化。

54.1. 概述 #

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

在正常操作中,前端向后端发送查询及其他命令,后端则返回查询结果和其他响应。少数情况下(例如 NOTIFY),后端会发送未请求的消息,但会话中的绝大多数交互仍由前端请求驱动。

会话通常由前端选择终止,但在某些情况下也可能由后端强制终止。无论哪种情况,后端关闭连接时,都会在退出前回滚所有打开的(未完成的)事务。

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

正常操作还包含用于 COPY 等特殊操作的额外子协议。

54.1.1. 消息概述 #

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

为了避免与消息流失去同步,服务器和客户端通常都会先根据字节计数把整条消息读入缓冲区,然后再处理其内容。这样一来,如果在处理内容时检测到错误,就比较容易恢复。在极端情况下(例如没有足够内存缓冲整条消息),接收方也可以利用字节计数判断在恢复读取消息之前需要跳过多少输入。

反过来,服务器和客户端也必须注意绝不能发送不完整的消息。通常的做法是在开始发送之前,先在缓冲区中完成整条消息的编组。如果在发送或接收消息的途中发生通信故障,唯一合理的做法就是放弃连接,因为几乎不可能重新恢复消息边界的同步。

54.1.2. 扩展查询概述 #

在扩展查询协议中,SQL 命令的执行被拆分为多个步骤。各步骤之间保留的状态由两类对象表示:预备语句和 portal。预备语句表示对文本查询字符串完成解析和语义分析后的结果。预备语句本身还不能直接执行,因为它可能缺少特定的参数值。portal 表示一条已经可以执行、或已经部分执行过的语句,其中所有缺失的参数值都已补齐。(对于 SELECT 语句,portal 等价于一个打开的游标;但由于游标不能处理非 SELECT 语句,这里采用不同术语。)

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

后端可以跟踪多个预备语句和 portal(但请注意,它们只存在于单个会话内,绝不会在会话之间共享)。已有的预备语句和 portal 都通过创建时赋予的名称来引用。此外,还存在一个“未命名”的预备语句和 portal。虽然它们的行为与有名对象大体相同,但对未命名对象的操作是为“只执行一次然后丢弃”的场景优化的,而对有名对象的操作则是基于会被多次使用的预期进行优化的。

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 中引入。更早版本在客户端请求不支持的次版本时会直接拒绝连接。

表 54.1 给出了当前支持的协议版本。表 54.2 说明了不受支持或保留的协议版本。

表 54.1. 支持的协议版本

版本支持范围说明
3.2PostgreSQL 18 及以后当前最新版本。用于取消查询的密钥从 4 字节扩展为可变长度字段。BackendKeyData 消息已作相应调整,CancelRequest 消息则重新定义为使用可变长度负载。
3.0PostgreSQL 7.4 及以后 

表 54.2. 其他协议版本

版本支持范围说明
3.9999-保留用于协议防僵化测试(greasing)。libpq 可能会使用这个版本,它高于项目预期会用到的任何次版本,用于测试服务器和中间件是否正确实现协议版本协商。服务器不得为这个版本加入特例逻辑;它们只需把它与自己支持的最新版本比较(后者总会更小),然后通过 NegotiateProtocolVersion 消息进行降级。
3.1-保留。PostgreSQL 从未使用 3.1;之所以跳过该版本,是因为广泛使用的 pgbouncer 的旧版本在协议协商中存在缺陷,会错误宣称支持 3.1。
2.0至 PostgreSQL 13已废弃。详见旧版本 PostgreSQL 文档。

54.1.5. 协议扩展 #

服务器和客户端还可以就当前使用的协议版本中的单项扩展进行协商。这些扩展由客户端在启动消息中作为特殊命名的参数提供,参数名前缀为 _pq_.。服务器会通过发送 NegotiateProtocolVersion 消息来拒绝任何未知或不受支持的扩展,并在消息中给出被拒绝的参数名列表,随后客户端可以选择是否继续连接。表 54.3 和表 54.4 分别记录了受支持的协议扩展参数和保留的协议扩展参数。

表 54.3. 受支持的协议扩展

参数名值支持范围说明
    (当前未定义任何受支持的协议扩展。)

表 54.4. 保留的协议扩展

参数名说明
_pq_.[name]上面未定义的、任何其他以 _pq_. 开头的参数名都保留供未来协议扩展使用。服务器必须拒绝从客户端收到的任何这类参数,并在启动流程中通过发送 NegotiateProtocolVersion 消息来完成这一点,然后应继续处理连接的其他部分。
_pq_.test_protocol_negotiation保留用于协议防僵化测试(greasing)。libpq 可能发送这个扩展,用于测试服务器和中间件是否正确实现协议扩展协商。服务器不得为这个参数加入特例逻辑;它们只需通过 NegotiateProtocolVersion 消息发送所有不受支持选项的列表(包括这个选项)即可。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.