通义千问对postgresql wire协议的连接和执行SQL过程的解释
USER
请说明postgresql wire协议的连接和执行SQL过程
ASSISTANT
PostgreSQL Wire Protocol(也称“前端-后端协议”或“FE/BE协议”)是客户端与PostgreSQL服务器通信的标准二进制协议。它定义了客户端如何连接、认证、发送查询、接收结果等全过程。协议支持两种模式:简单查询协议(Simple Query Protocol) 和 扩展查询协议(Extended Query Protocol)。下面我们将详细说明连接建立和SQL执行的全过程。
一、连接建立过程
1. TCP连接建立
客户端首先通过TCP连接到PostgreSQL服务器的监听端口(默认5432)。
2. 启动消息(StartupMessage)
客户端发送一个 StartupMessage(消息类型无类型字节,长度字段后紧跟协议版本和参数键值对),包含:
- 协议版本号(如 3.0 → 0x00030000)
- 连接参数:如
user
,database
,application_name
,client_encoding
等
示例:
| 长度(4B) | 协议版本(4B) | "user\0postgres\0database\0mydb\0\0" |
注意:StartupMessage 是唯一没有消息类型字节的消息。
3. 服务端响应
服务器根据配置和StartupMessage内容,可能返回以下消息:
- AuthenticationXXX(如 AuthenticationMD5Password, AuthenticationSASL 等)
- ErrorResponse(连接失败)
- BackendKeyData(会话密钥,用于取消查询)
- ParameterStatus(服务器参数,如 client_encoding, DateStyle 等)
- ReadyForQuery(表示可以接收查询了,状态字符:I-空闲,T-事务中,E-错误)
认证过程(以MD5为例):
- 服务端发送
AuthenticationMD5Password
+ 4字节盐值。 - 客户端计算:
MD5(MD5(password + username) + salt)
,发送PasswordMessage
。 - 服务端验证,成功则发
AuthenticationOk
。
4. 连接建立完成
当客户端收到 ReadyForQuery
消息后,连接正式建立,可以开始发送SQL命令。
二、SQL执行过程
PostgreSQL支持两种协议模式执行SQL:
A. 简单查询协议(Simple Query Protocol)
适用于一次性、无参数、不复用的SQL语句。
流程:
-
客户端 → 服务端: 发送
Query
消息
格式:'Q' + 长度 + SQL字符串 + '\0'
示例:
Q | len=19 | "SELECT 1 + 1;\0"
-
服务端响应:
RowDescription
:描述结果集列(列名、类型OID、格式等)DataRow
:每一行数据(二进制或文本格式)CommandComplete
:查询完成,包含命令标签(如 “SELECT 1”)ReadyForQuery
:准备接收下一条命令
如果有错误,服务端发送
ErrorResponse
,然后仍会发送ReadyForQuery
。
特点:
- 简单直接,适合交互式工具(如 psql)
- 不支持参数化查询
- 每次查询都完整解析、计划、执行
- 无预备语句支持
B. 扩展查询协议(Extended Query Protocol)
支持参数化查询、预备语句、查询计划复用,适合高性能应用(如 JDBC、Go pgx、Python psycopg2)。
主要消息类型:
消息类型 | 说明 |
---|---|
Parse | 解析SQL,生成预备语句(可命名或匿名) |
Bind | 绑定参数值到预备语句,生成“入口”(Portal) |
Describe | 获取预备语句或入口的元数据(如列信息) |
Execute | 执行入口 |
Sync | 同步点,强制服务端返回所有结果直到 ReadyForQuery |
Close | 关闭预备语句或入口 |
典型流程(带参数查询):
-
Parse
'P' + len + stmt_name + query + param_type_count + [param_type_oid...]
→ 服务端返回
ParseComplete
(或ErrorResponse
) -
Bind
'B' + len + portal_name + stmt_name + param_format_codes + [param_values...] + result_format_codes
→ 服务端返回
BindComplete
-
Describe(可选)
用于获取结果集结构(如列名、类型):'D' + len + 'P'(Portal)或'S'(Statement) + name
→ 服务端返回
RowDescription
或NoData
(如INSERT无结果) -
Execute
'E' + len + portal_name + max_rows(0=无限制)
→ 服务端返回:
DataRow
(0或多个)CommandComplete
- (如有错误 →
ErrorResponse
)
-
Sync
'S' + len=4
→ 服务端必须返回
ReadyForQuery
,保证协议同步 -
Close(可选)
清理资源:'C' + len + 'S'或'P' + name
示例:执行 SELECT * FROM users WHERE id = $1
→ Parse(stmt="", query="SELECT * FROM users WHERE id = $1", types=[int4])
← ParseComplete→ Bind(portal="", stmt="", params=[123])
← BindComplete→ Describe(portal="")
← RowDescription(columns=[...])→ Execute(portal="", max_rows=0)
← DataRow(...)
← CommandComplete("SELECT 1")
← ReadyForQuery('I')
三、事务与错误处理
- 事务控制:通过SQL语句
BEGIN
,COMMIT
,ROLLBACK
控制,协议本身无事务消息。 - 错误处理:任何阶段出错,服务端发送
ErrorResponse
,然后必须发送ReadyForQuery
。客户端可继续发送新命令。 - 取消查询:客户端可通过
CancelRequest
消息(独立TCP连接)中断正在执行的查询。
四、连接关闭
客户端发送 Terminate
消息(‘X’ + 4字节长度),服务端关闭连接。
五、协议版本与兼容性
- 当前主流版本:v3.0(自 PostgreSQL 7.4 起使用)
- SSL支持:连接建立后可通过
SSLRequest
升级为加密连接 - GSSPI/SASL:现代认证机制也通过协议协商支持
总结对比
特性 | 简单查询协议 | 扩展查询协议 |
---|---|---|
参数化 | ❌ 不支持 | ✅ 支持 |
性能 | 较低(每次解析) | 较高(可复用执行计划) |
使用场景 | psql、简单脚本 | 应用程序、驱动、ORM |
消息复杂度 | 简单 | 复杂(多阶段) |
结果集预知 | 执行后才知道 | 可提前Describe获取结构 |
参考资料
- PostgreSQL官方文档:Frontend/Backend Protocol
- Wire协议消息格式详解:Message Flow
通过理解Wire协议,开发者可以更好地调试数据库交互、编写高性能驱动、或实现自定义客户端。主流语言驱动(如 libpq、pgx、psycopg2)均基于此协议实现。