db.pg
since: std-0.5 stability: experimental
PostgreSQL 线协议 v3 核心(§12;P5-C;回放优先架构) ═══ 架构口径(控制器裁定;P5 计划 Task 3)═══ 协议核消费"注入源"帧:双薄源共驱一核—— ① pg_recv_frame_script(回放源):List[Str] 十六进制帧逐帧出(录制/手工 按协议文档构造;tests/db/replay_fixtures/.script + README)——CI 零真库; ② pg_recv_frame_fd(真源):fd 直读(db 自有垫片 db/c_src/ ctron_dbpg.c,镜像 ctron_net.c 约定;真 fd 冒烟 Task 6 nightly)。 Ctron 无可发射 trait ⇒ 既定双入口形态:两入口 fn 共享核心解析器 (pgx_),统一产出 PgRecv(帧面)/PgRows/PgSess(会话面)。 ═══ 依赖纪律 ═══ 单子扩展(P5-D 落定):唯一 std 依赖 = std.crypto(SCRAM 原语 sha256_bytes/hmac_sha256/pbkdf2_sha256;ws.ct→std.crypto 同款单子先例, E5020 树互斥)。base64 不取 std/enc——其 b64 面受 C8 printable-ASCII 约束,SCRAM 盐/证明/签名携任意字节(ws.ct lane-b64 同款先例),本文件 自出 pg_b64_encode/pg_b64_decode(List[I32] 字节容器,RFC 4648 标准 字母表 + '=' 填充)。不 use std.net(Global Constraints):真源经 PgCell64 标量胞(本文件自有声明;与 net bind.ct 的 Box64 同布局异名 ——同名 decl 二次合并 E5030,合并单命名空间纪律)传 fd,垫片符号 前缀 ctron_dbpg_。SCRAM 客户端 nonce 真熵经 ctron_dbpg_entropy (P5-D 新 extern;db 垫片别名转发 ctron_entropy_fill——pg.ct 直宣 ctron_entropy_fill 与 std/uuid.ct 同名 decl 合并即 E5030,探针实证, 故出 db 前缀别名;链接需并链 ctron_entropy.c)。 ═══ 发射面/解释面纪律(divergences (f)-(i) + P5 新证)═══ ① (h) 载荷通道:跨模块数值消费一律 struct 标量字段 + 自由 getter (client.ct HttpLoc/HttpResp 同款);Result 数值载荷禁跨模块。 ② (i) C10:长度/计数算术一律宽域播种(pgz)后乘法;帧长域门 [4, 1048576](2^20,远低 2^28 险带);BE 解析乘前高位预门; 装配侧全走 div/mod(乘法仅 256 阶梯,值域 ≤2^20)。 发射面 List[I64] struct 字段元素读坏(items 按 char 出)——探针 实证 P5-C 登记 divergences;本文件 struct 字段只用 List[Str]/ List[I32]。 ③ utf8_enc 解释口径坏(恒返 U+FFFD;自举 eval 值串未转 int——P5-C 登记 divergences):单元格 Str 解码走可打印 ASCII 表切片 (client.ct cx_slice_str 同款,双臂确定性;'{' 档 fail-closed); 任意字节精确面 = pg_hex_encode/pgr_cell_hex(List[I32] 字节容器, crypto 面纪律);非 ASCII 文本解码待解释器修复后收敛(登记口径)。 表切片内建收 I32 域标签:入参恒 I32,pgz 宽域值禁直入(解释口径 arity 拒;client.ct lane 值同域先例)。 ④ 无方法调用/无闭包/无 Tuple;while 体无 Drop 局部;状态随值携带 (message.ct ChunkSt 重入口径);List 经形参 push 跨函数传播 (parse_pkg.ct diags 同款已证形);"fn 内未用结果绑定"毒化纪律—— 绑定必消费,忽略返回值用裸语句形。 ⑤ inline test 不落本文件(C17 宿主敏感,P5-A 口径);声明冒烟 + 行为面全在 tests/db。 ═══ 线协议范围(本任务;P5-D 扩)═══ startup(3.0 + 参数面)/AuthenticationOk 检测/SCRAM-SHA-256 全流程 (RFC 5802/7677;gs2 'n' 档,channel-binding-plus 不支援即 clean Err; pg_scram_handshake 回放面 + pg_scram_ 纯核)/Query 简单查询/ 扩展查询装配(Parse/Bind/Describe/Execute/Close/Sync + 管线拼接; 收侧与简单查询共驱一核——1/t/2/n 帧入"其余跳过"前向兼容)/ 事务面(BEGIN/COMMIT/ROLLBACK Query 面 + ReadyForQuery 'T'/'I'/'E' 状态字节 + 取消传播:pg_conn_dirty 脏/排空分级 + 复位语义)/ RowDescription/DataRow(文本格式)/CommandComplete/ReadyForQuery/ ErrorResponse(全字段解析,暴露 severity+SQLSTATE+message)/ NoticeResponse 跳过/ParameterStatus 跳过/BackendKeyData 解析/ CancelRequest 装配(独立连startup 形)*/Terminate。大端长度前缀帧: server 帧 [type(1)|len(4,含自身)|payload];client 帧 startup/cancel 无 type 字节,其余有。 ═══ err 码(PgRecv.err/PgRows.err/PgSess.err)═══ 1 帧面坏(非十六进制/空行) 2 协议违例(长度域/字段越界/计数不符/ SCRAM 相位错) 3 源耗尽(脚本走完/fd 对端关) 4 认证败(SCRAM 签名 不符/nonce 前缀违例/盐·迭代·机制面坏;Cleartext/MD5 存根) 5 ErrorResponse 收到(SQLSTATE 在 ecode) 6 IO(fd 读写败;fd 源专面) rc 约定:0 成功 / <0 失败(net 门面同款)。
pub struct
struct PgCell64
fd 出参标量胞(与 net bind.ct Box64 同布局异名;见头注依赖纪律);
出参持态一律 BoxPgCell64
| Field | Type |
|---|---|
var v |
I64 |
struct PgRecv
| Field | Type |
|---|---|
var rc |
I64 |
var err |
I64 |
var next |
I64 |
var mtype |
I32 |
var body |
List[I32] |
struct PgErrData
ErrorResponse/NoticeResponse 字段面:code(1B) + cstring 值,0x00 终。
S/V → severity,C → SQLSTATE,M → message,其余字段跳过(全字段扫描,
暴露面只取标准三槽)。无终止 NUL → ok=0。
| Field | Type |
|---|---|
var ok |
I64 |
var sev |
Str |
var code |
Str |
var msg |
Str |
struct PgRows
查询结果(struct 通道;头注①)——cells/nulls 行主序平铺;
cbytes/coffs 承载逐格原始字节(精确面;ASCII 面经 pgx_ascii_bytes;
List[I64] 字段发射面坏 ⇒ offsets 用 List[I32],帧长域 2^20 内恒安全)
| Field | Type |
|---|---|
var rc |
I64 |
var err |
I64 |
var nrows |
I64 |
var ncols |
I64 |
var tag |
Str |
var cols |
List[Str] |
var oids |
List[I32] |
var cells |
List[Str] |
var nulls |
List[I32] |
var cbytes |
List[I32] |
var coffs |
List[I32] |
var esev |
Str |
var ecode |
Str |
var emsg |
Str |
var next |
I64 |
var status |
I64 |
struct PgSess
| Field | Type |
|---|---|
var rc |
I64 |
var err |
I64 |
var next |
I64 |
var status |
I64 |
var pid |
I64 |
var key |
I64 |
var authkind |
I64 |
var esev |
Str |
var ecode |
Str |
var emsg |
Str |
var mechs |
List[Str] |
var cfirst |
Str |
var sfirst |
Str |
var cfinal |
Str |
var sigok |
I64 |
pub fn
| Signature | Returns | Description |
|---|---|---|
pg_frame_max() |
I64 |
— |
pg_err_frame() |
I64 |
— |
pg_err_proto() |
I64 |
— |
pg_err_eof() |
I64 |
— |
pg_err_auth() |
I64 |
— |
pg_err_response() |
I64 |
— |
pg_err_io() |
I64 |
— |
pg_hex_decode(s: Str) |
List[I32] |
十六进制串 → 字节表(0..255);奇长/非法数位/空串 → 空表(fail-closed) |
pg_hex_encode(b: List[I32]) |
Str |
字节表 → 小写十六进制串(空表 → "") |
pg_body_ascii(b: List[I32], a: I64, e: I64) |
Str |
ASCII 文本面 pub 形(P5-F:fd 真源消费方/nightly 需 body → 文本,如 SCRAM server-first 提取)。界外/非可打印 → ""(fail-closed 同上)。 |
pgv_rc(r: PgRecv) |
I64 |
— |
pgv_err(r: PgRecv) |
I64 |
— |
pgv_next(r: PgRecv) |
I64 |
— |
pgv_type(r: PgRecv) |
I32 |
— |
pgv_body_len(r: PgRecv) |
I64 |
— |
pgv_body_at(r: PgRecv, i: I64) |
I32 |
— |
pgv_body(r: PgRecv) |
List[I32] |
— |
pg_recv_frame_script(frames: List[Str], cur: I64) |
PgRecv |
① 回放源:十六进制帧脚本逐帧出(List[Str] 一帧一行;cur 越界 → eof) |
pg_recv_frame_fd(fd: I64, rbuf: &[I64], fill: Box[PgCell64], scr: &[I64]) |
PgRecv |
② 真源:fd 直读(阻塞;真 fd 冒烟 Task 6 nightly;x_ 夹具 emit 臂专面)。 rbuf = 持续读缓冲 lane(须 ≥ frame_max+1 lane;调用方持有;view .len = 字面量显式槽数——夹具逐槽写满字面量,tcp_echo 同款),fill = 缓冲填充位 标量胞(Box[PgCell64];net 出参 Box[Box64] 同款堆胞——struct 值语义下 裸形参写回是 callee 局部拷贝,跨调用持态必须经 Box),scr = 单读暂存 lane(垫片 CT_CHUNK=4096 口径)。声明长越域 → err 2;读败 → err 6; 对端关 → err 3;守卫计数防滞留(长度域已门,滞留面只剩对端慢滴, nightly 面再演进)。mtype 在 leftover 前移前捕获(管线帧场景:一包 R+S+K+Z 到齐,shift 后 rbuf[0] 已是下一帧类型字节)。 |
pg_send_msg_fd(fd: I64, msg: List[I32], scr: &[I64]) |
I64 |
客户端帧发送(fd 源;List → lane 暂存后整发;rc 0 成/<0 败;超暂存 → -1)。垫片 write 为 send-all 整长 chunk 循环(ctron_net.c ct_send_all 同口径,无静默截断),返回值语义 = 已发全长的确认。 |
pg_fd_close(fd: I64) |
I64 |
— |
pg_fd_last_errno() |
I64 |
— |
pg_startup_msg(user: Str, database: Str, app: Str) |
List[I32] |
startup 协议 3.0(版本 196608 = 3<<16):user 恒在;database/ application_name 非空才入参数面;尾 NUL 终止参数序列 |
pg_query_msg(sql: Str) |
List[I32] |
Query 简单查询帧('Q' + sql + NUL) |
pg_password_msg(pw: Str) |
List[I32] |
CleartextPassword 应答帧('p' + 密码 + NUL;存根面,Task 4 SCRAM 接管) |
pg_terminate_msg() |
List[I32] |
Terminate('X' + len 4) |
pg_sasl_initial_msg(mech: Str, initial: List[I32]) |
List[I32] |
SASLInitialResponse('p'):机制名 + i32 初始响应长(-1 = 无)+ 初始响应 (gs2 头 + client-first-bare;'n' 档 = "n,," 前缀) |
pg_sasl_response_msg(resp: List[I32]) |
List[I32] |
SASLResponse('p'):client-final-message("c=biws,r=...,p=<proof-b64>") |
pg_parse_msg(stmt: Str, sql: Str, oids: List[I32]) |
List[I32] |
Parse('P'):语句名 + SQL + 参数 OID 表(0 = 未指定) |
pg_bind_msg(portal: Str, stmt: Str, params: List[Str], nulls: List[I32]) |
List[I32] |
Bind('B'):portal + 语句 + 参数(format code 0 逐参;值文本格字节, NULL = -1 长)+ result format 计数 0(全文本)。参数计数 i16 域门 (>65535 → 空表 fail-closed,(i) 族同门:计数先于 be16 装配) |
pg_describe_msg(kind: I32, name: Str) |
List[I32] |
Describe('D'):kind 'S'(83)= 语句 / 'P'(80)= portal + 名 |
pg_close_msg(kind: I32, name: Str) |
List[I32] |
Close('C'):kind 同 Describe;语句清理(归池复位三件套之一,Task 5 消费) |
pg_execute_msg(portal: Str, maxrows: I64) |
List[I32] |
Execute('E'):portal + max-rows(0 = 全行) |
pg_sync_msg() |
List[I32] |
Sync('S'):扩展查询管线收口(事务边界由 ReadyForQuery 报) |
pg_ext_pipeline(stmt: Str, sql: Str, oids: List[I32], portal: Str, params: List[Str], nulls: List[I32], maxrows: I64) |
List[I32] |
参数化查询管线一发(stmt/portal 名显参 = 预编译句柄命名面): Parse + Bind + Describe(portal) + Execute + Sync |
pg_tx_begin_msg() |
List[I32] |
begin/commit/rollback = Query 简单查询(会话语义收 ReadyForQuery 状态 字节:'I'=73 idle / 'T'=84 in-tx / 'E'=69 failed-tx;pg_query_script status 槽承接,tx 链 = 游标续跑) |
pg_tx_commit_msg() |
List[I32] |
— |
pg_tx_rollback_msg() |
List[I32] |
— |
pg_cancel_msg(pid: I64, key: I64) |
List[I32] |
CancelRequest(独立连 startup 形:无 type 字节,len 16,code 80877102, pid + key = BackendKeyData 回执面);收侧 Abort 面服务端自理 |
pg_conn_dirty(err: I64) |
I64 |
取消传播分级(池回池复位判定基面;Global Constraints:禁止跨取消复用 脏连接): 0 = clean(查询 rc 0,Z 已收,连接即复用) 2 = drain(E 已收口——含 57014 查询取消/25P02 事务内错——尾随 Z 在线, 复位 = 排空 Z(pgr_next 续跑)→ 事务内则 ROLLBACK → 见 Z('I') 复用) 1 = dirty(帧/协议/源耗尽/IO:流信任失,连接弃用,不复位不回池) 注:本分类只按 err 面;事务态 Z('T')(含 drain 排出 Z('T'))不在此 反映——池消费方回池前须另查 pgr_status,'T' 者先 ROLLBACK 见 'I' 再入池。 |
pg_dirty_clean(state: I64) |
I64 |
复用判定(1 = 可复用 / 0 = 需复位或弃用) |
pg_auth_kind(body: List[I32]) |
I64 |
Authentication 消息体 → 认证方式(0 Ok/3 Cleartext/5 MD5/10 SASL/…; 越界/畸形 → -1) |
pg_ready_status(body: List[I32]) |
I64 |
ReadyForQuery 体 → 事务状态字节('I'/'T'/'E';畸形 → -1) |
pg_tag(body: List[I32]) |
Str |
CommandComplete 体 → tag 文本(可打印 ASCII;畸形/非打印 → "") |
pge_ok(e: PgErrData) |
I64 |
— |
pge_sev(e: PgErrData) |
Str |
— |
pge_code(e: PgErrData) |
Str |
— |
pge_msg(e: PgErrData) |
Str |
— |
pg_err_data(body: List[I32]) |
PgErrData |
— |
pgr_rc(r: PgRows) |
I64 |
— |
pgr_err(r: PgRows) |
I64 |
— |
pgr_rows(r: PgRows) |
I64 |
— |
pgr_cols(r: PgRows) |
I64 |
— |
pgr_tag(r: PgRows) |
Str |
— |
pgr_colname(r: PgRows, i: I64) |
Str |
— |
pgr_oid(r: PgRows, i: I64) |
I64 |
类型 OID(u32 档 ≥2^31 按 I32 符号化呈现,头注②;OOB → -1) |
pgr_isnull(r: PgRows, row: I64, col: I64) |
I64 |
— |
pgr_cell(r: PgRows, row: I64, col: I64) |
Str |
— |
pgr_cell_hex(r: PgRows, row: I64, col: I64) |
Str |
格精确字节面(十六进制;任意字节双臂可断言;OOB → "") |
pgr_cell_bytes(r: PgRows, row: I64, col: I64) |
List[I32] |
— |
pgr_esev(r: PgRows) |
Str |
— |
pgr_ecode(r: PgRows) |
Str |
— |
pgr_emsg(r: PgRows) |
Str |
— |
pgr_next(r: PgRows) |
I64 |
会话游标(P5-D):next = 收侧消费停点(Z 之后 = 后续查询续跑位;E 之后 = 尾随 Z 待排空位——drain 面,自 next 续跑即排空);status = ReadyForQuery 状态字节('I'=73/'T'=84/'E'=69;未见 Z = 0)。事务链/取消复位面基石。 |
pgr_status(r: PgRows) |
I64 |
— |
pg_query_script(frames: List[Str], cur: I64, sql: Str) |
PgRows |
查询回放(脚本源;收侧核 = 简单查询与扩展查询响应流共驱——扩展查询的 ParseComplete('1')/BindComplete('2')/ParameterDescription('t')/NoData ('n')入"其余跳过"前向兼容,v0 不校验计数(登记口径)):发侧由调用方 构建/断言(回放源无下行信道;扩展查询装配 pg_ext_pipeline);收侧逐帧: T→行描述,D→行(列数校验),C→tag,Z→收口(rc 0,next 推进 + status 记), E→rc -1 err 5 + 字段面(next 停在尾随 Z 之前 = 排空位),N/S/K/其余→跳过 (前向兼容)。源耗尽未见 Z → err 3。无行集查询(BEGIN 等)rc 0 ncols 0。 next/status 语义见 pgr_next(pgr)。 |
pg_query_fd(fd: I64, rbuf: &[I64], fill: Box[PgCell64], scr: &[I64]) |
PgRows |
② 真源查询收帧(P5-F nightly;pg_query_script 的 fd 薄源镜像——帧分派 核同构:R84 行描述/D68 数据行/C67 tag/Z90 收口/E69 错误,其余帧跳过 前向兼容;扩展查询响应面 1/2/t/n 同核)。发侧(Query/Sync/管线)由调用 方经 pg_send_msg_fd 装配;本入口自 fd 收帧至 Z/E/源尽。next 恒 0(fd 源 无脚本游标;留 fill/rbuf 持态续用)。阻塞 fd:pg_recv_frame_fd 循环至 整帧。守卫计数防滞留(对端慢滴/僵连面由调用方超时策略兜,v0 登记)。 |
pgs_rc(s: PgSess) |
I64 |
— |
pgs_err(s: PgSess) |
I64 |
— |
pgs_next(s: PgSess) |
I64 |
— |
pgs_status(s: PgSess) |
I64 |
— |
pgs_pid(s: PgSess) |
I64 |
— |
pgs_key(s: PgSess) |
I64 |
— |
pgs_authkind(s: PgSess) |
I64 |
— |
pgs_esev(s: PgSess) |
Str |
— |
pgs_ecode(s: PgSess) |
Str |
— |
pgs_emsg(s: PgSess) |
Str |
— |
pgs_nmech(s: PgSess) |
I64 |
SCRAM 面(P5-D):mechs = AuthenticationSASL 机制列表;cfirst/sfirst/ cfinal = client-first-bare / server-first-message / client-final-message (含 ,p= 证明);sigok = server-final 签名校验(1 符 / 0 不符 / -1 未达)。 |
pgs_mech(s: PgSess, i: I64) |
Str |
— |
pgs_cfirst(s: PgSess) |
Str |
— |
pgs_sfirst(s: PgSess) |
Str |
— |
pgs_cfinal(s: PgSess) |
Str |
— |
pgs_sigok(s: PgSess) |
I64 |
— |
pg_handshake_script(frames: List[Str], cur: I64) |
PgSess |
握手回放:startup 发侧由调用方构建/断言(回放源无下行信道);收侧 R(AuthenticationOk=0 续;Cleartext=3/MD5=5 存根 err 4;SASL=10 → 本入口 不携凭据,err 4 指路 pg_scram_handshake),K 记 pid/key,E 记字段面, Z 记 status 收口。源耗尽 → err 3。SCRAM 全流程 = pg_scram_handshake。 |
pg_b64_encode(b: List[I32]) |
Str |
字节表 → base64 串(RFC 4648 标准字母表 + '=' 填充) |
pg_b64_decode(s: Str) |
List[I32] |
base64 串 → 字节表;长度非 4 倍/非法数位/垫位错位(中段 '=')→ 空表 (fail-closed;空串 → 空表,调用方以盐长 0 拒) |
pg_str_bytes(s: Str) |
List[I32] |
Str → 字节表(ASCII 域;byte_at 逐字节;AuthMessage/口令边) |
pg_scram_first_bare(user: Str, nonce: Str) |
Str |
client-first-message-bare = "n=" + user(或 authzid)+ ",r=" + nonce |
pg_scram_salted(pass: Str, salt: List[I32], iters: I32) |
List[I32] |
SaltedPassword = PBKDF2-HMAC-SHA256(口令字节, 盐, i;32B) |
pg_scram_proof(salted: List[I32], authmsg: Str) |
List[I32] |
ClientProof = ClientKey XOR ClientSignature(= HMAC(StoredKey, AuthMessage); authmsg 由调用方按上式拼) |
pg_scram_server_sig(salted: List[I32], authmsg: Str) |
List[I32] |
ServerSignature = HMAC(HMAC(SaltedPassword,"Server Key"), AuthMessage) |
pg_scram_nonce_from(rand: List[I32]) |
Str |
18B 随机 → 24 字符 b64 nonce(RFC 5802 建议 nonce 熵 ≈ 18 字节档; 纯形:调用方供熵,双臂可测) |
pg_scram_nonce() |
Str |
真熵 nonce(发射臂面;interp 无 extern 运行时——uuid_v4 同款口径); 失败 → 空串(fail-closed,绝不回退伪熵)。lane 槽数 = 字面量显式 (P5-C 登记:lane .len = 字面量槽数)。 |
pg_scram_handshake(frames: List[Str], cur: I64, user: Str, pass: Str, nonce: Str) |
PgSess |
SCRAM-SHA-256 握手回放(frames[cur..];发侧 SASLInitialResponse/ SASLResponse 由调用方经 pg_sasl__msg 装配并断言,回放源无下行信道): R kind 10(机制表;明档选择)→ kind 11(server-first:nonce 前缀校验/ 盐 b64 解码/迭代 (i) 门 → PBKDF2 → client-final 计算面入 sess)→ kind 12(server-final v= 与本地 ServerSignature 比对,不符 → err 4 认证败)→ AuthOk/K/Z 收口(status 记;Z 门 phase==3——未见 R12 校验 通过的收口一律 rc<0 err 4,信任面。E → err 5 字段面。相序违例 (11/12 先于 10 / 12 先于 11)→ err 2。空 nonce → err 4(fail-closed: 前缀校验空洞)。sigok/pgs_ 面 = 夹具逐字节锚定面。 |
pg_scram_handshake_fd(fd: I64, rbuf: &[I64], fill: Box[PgCell64], scr: &[I64], user: Str, pass: Str, nonce: Str) |
PgSess |
② 真源 SCRAM-SHA-256 握手(fd 直读直发;pg_scram_handshake 的 fd 镜像 + 下行信道):调用方先 pg_send_msg_fd 发 startup,再入本入口。相序门 (R10→R11→R12→AuthOk/K/S→Z)/ 机制明档选择 / nonce 前缀校验 / 盐-迭代 (i) 门 / server-final v= 校验 / Z 门 phase==3 信任面(P5-D 评审 必修同门:未见 R12 校验通过的收口一律 rc<0 err 4)/ kind 3/5 clean Err 4 —— 全与脚本源逐条一致。fd 差分:R10 后发 SASLInitialResponse ("n,," + client-first-bare),R11 后发 SASLResponse(client-final); 发败 → err 6。kind 0 直达(trust 等)同脚本源口径:phase 门照收,不作 成功面(Z 门拦截)。next 恒 0(fd 源无脚本游标)。 |
sha256_hex(msg: Str) |
Str |
— |
sha1_hex(msg: Str) |
Str |
— |
sha256_bytes(msg: List[I32]) |
List[I32] |
— |
hmac_sha256(key: List[I32], msg: List[I32]) |
List[I32] |
— |
pbkdf2_sha256(pass: List[I32], salt: List[I32], iters: I32, dklen: I32) |
List[I32] |
— |
bytes_to_hex(b: List[I32]) |
Str |
— |
bytes_from_hex(s: Str) |
List[I32] |
— |