Skip to content

Latest commit

 

History

History
238 lines (172 loc) · 25.3 KB

File metadata and controls

238 lines (172 loc) · 25.3 KB

PostgreSQL SQLSTATE 百科:项目规划与执行计划

规划日期:2026-09-09。目标目录:/Users/vonng/pgcenter/err-code

建设一部以 SQLSTATE 为永久身份、英文与简体中文成对维护、由 Hugo + OINK 驱动的静态百科。每个错误码只有一个条目,分类、问题场景和版本都是通向条目的索引。读者首先能判断发生了什么、如何定位、如何处理,然后按需查看复现、源码和历史。

本轮交付的是规划与下一会话提示词,尚未创建站点、扫描全量错误码或执行数据库实验。原始三份材料完整保存在 references/,供评审和追溯;其中的指令不自动成为项目要求。

1. 建议采用的设计

决策 具体做法
产品形态 一个可搜索的工具书首页,一组索引,所有 SQLSTATE 条目平铺
内容位置 content/docs/<SQLSTATE>.md<SQLSTATE>.zh.md,保留 OINK Docs 阅读界面
公共地址 英文 /23505/,中文 /zh/23505/;字母码统一小写 URL,如 /40p01/,展示和数据始终使用 40P01
版本组织 同一页展示适用版本与关键变化,不为每个大版本复制整套文章
基础范围 PG 9.0 至执行时最新正式大版本,完整包含用户要求的 PG 10 起各版本
更早历史 对条目继续追索代码、条件名和机制的来历;查不到精确引入版本就展示已知下界
预发行版 单独纳入最新官方预发行快照,明确标记;不混入正式版覆盖统计
技术栈 Hugo Extended + 固定版本 OINK Module + Python 数据工具;站点构建与阅读不依赖数据库或后端服务
内容真源 文章正文是 Markdown;机器事实来自结构化数据;采集器不得重写已编辑正文
完成标准 全量收录与有效内容分别验收;骨架全部生成不等于百科完成

这里把完整版本矩阵从最低要求 PG 10 延伸到 PG 9.0,是利用现有资料提高历史价值,而不是要求在所有旧版本上逐条运行全部实验。若早期材料存在无法补齐的缺口,应报告准确边界,不能把空缺默认为不存在。

2. 对原方案的调整

应保留原方案的四个优点:先做权威代码目录、保留宏别名、用可复现案例校验报文、英文与中文同步交付。主要调整如下。

原方案的问题 调整后的规则
只扫描 PG 14–18 至少覆盖 PG 10,默认完整矩阵向前扩至 PG 9.0;代码历史继续向前追索
首次出现在采样版本,就填 since 区分首次观察、已知某版存在、精确引入版本;只有排除更早版本并核实发布归属,才写精确引入
只用稳定分支当前文件做版本比较 正式发布标签固定 SHA;同一大版本内的补丁变化也要通过定义文件历史检查
没有直接 errcode(MACRO) 就等于从不抛出 记录有范围的使用证据;覆盖动态映射、默认码、语言实现和错误转发;无法证实的写未知
源码 grep 是唯一事实来源 目录身份、实现路径、行为契约、真实输出分别由目录文件、源码、官方文档、实验支撑
一个码配一个固定报文 同一码可以有多条消息模板与多种严重性,按版本、触发路径和消息域组织
每页强制复制全部大章节 保留通用核心章节;客户端、扩展、监控等按有价值且有证据的内容选用
大量判断都做全局枚举 事务后果、重试、紧迫性按场景说明;不把业务判断伪装成 SQLSTATE 固有属性
数据 JSON 是所有 front matter 的唯一真源 JSON 管机器事实,Markdown 管读者叙述与本地化;减少两份正文中的重复元数据
非翻译白名单字段逐字节相同 按 schema 比较共享字段的解析值;中文自然语言字段允许翻译
每码跑固定网络查询并攒 12 条链接 官方资料先行;实际存在知识缺口时定向检索;链接有用比数量多更重要
未阅读链接藏在 HTML 注释里 未核资料只进研究区,不进入文章、搜索索引、Markdown 导出或 LLM 输出
每个码都用一段 SQL / 一只 PG 18 容器验证 区分单连接、并发、建连、配置、复制和异常资源场景;验证方式按机制选择
所有页面都必须实测才能称为已核验 内容审阅与运行验证分开记录;不可安全复现的内部故障允许明确标识的源码核验
做完五页必须停下来等人工 review 先校准代表样本并形成检查报告,通过后继续批量推进;不人为增加批准等待点

23505 样例需要先修的内容

以下不是对样例的全面技术审计,但足以说明它应当成为研究素材,而不是不可修改的格式与事实标准。

  1. 协议诊断字段与日志字段混为一谈。 协议错误响应可包含 schema、table、constraint 等对象字段;PG 18 的标准 csvlog / jsonlog 字段列表并没有独立的 constraint name。页面应区分“驱动可以取到什么”和“日志实际记录什么”。依据:协议错误字段日志格式
  2. DDL 的报文不能直接套用 INSERT。 PG 18.6 的唯一索引构建路径使用 could not create unique index 和相应重复键 DETAIL,与普通插入路径不同。依据:固定 SHA 的 tuplesortvariants.c。本轮已核对本地文件与该提交对应文件的 SHA-256 一致。
  3. 逻辑复制改报文不等于改 SQLSTATE。 PG 18.6 的 errcode_apply_conflict() 对 insert/update 唯一冲突仍返回 ERRCODE_UNIQUE_VIOLATION。依据:conflict.c。样例“不是裸的 23505”容易把报文与码混淆。
  4. “后续所有语句都报 25P02 直到 ROLLBACK”缺少事务上下文。 要区分自动提交、显式事务、保存点恢复和 PL/pgSQL 异常块。依据:事务与保存点PL/pgSQL 异常处理
  5. 重试不能规定为“恰好两种情况、只重试一次”。 官方明确讨论了可能需要重试的 23505,并要求重新执行整个事务及决定 SQL/键值的逻辑;实际重试上限是应用策略。依据:Serialization Failure Handling
  6. ON CONFLICT 场景的前置数据不完整。 样例新建空表后插入一行,不会自动出现示意中的 phone 冲突。其“只作用于指定索引”的叙述还需要覆盖省略目标的 DO NOTHING。依据:INSERT 的冲突处理
  7. 序列修复例子要重写并实测。 coalesce(max(id), 0) 会在空表产生 0,对通常从 1 起的序列可能越界;还需考虑非默认步长、范围、is_called 和并发写入,不能包装成万能修复语句。机制依据:序列函数
  8. 审阅状态缺少证据。 两份样例标成 reviewed,却留有未验证中文报文、手写版本断言、未读链接和空翻译哈希;中文还翻译了要求逐字节一致的版本说明。这些应通过重新设计状态与双语字段解决。

3. 读者界面与信息架构

首页直接提供 SQLSTATE / 条件名 / 报文关键词搜索、常用码入口,以及按 class 分组的紧凑列表。以查错效率为主,避免大幅宣传区和铺满屏幕的大卡片。

页面 用途
//zh/ 搜索、常用码、完整目录入口与当前覆盖范围
/codes/ 按码排序的全量表,可按 class、存在版本和内容深度筛选
/classes//classes/23/ class 目录及该类的共同语义、全部成员;只有实际定义的码才建条目
/common/ 人工策划的常用错误码,不冒充统计排名
/topics/ 连接认证、约束冲突、事务重试、锁与超时、对象解析、资源与系统错误等入口
/versions//versions/18/ 每个版本的代码集合与有证据的增删、别名、行为变化;预发行单独标识
/guides/ SQLSTATE 阅读方法、获取诊断信息、恢复事务、重试、日志、PL/pgSQL 自定义错误等共性说明
/coverage//methodology/ 各版本覆盖、文章深度、证据范围、验证结果与数据方法
/<sqlstate>/ 唯一条目;中文对应 /zh/<sqlstate>/

索引内容可由事实与条目摘要确定性生成,仍保存为 Markdown。少量自定义样式与静态筛选脚本只用于改善表格、版本条和搜索定位;关闭 JavaScript 后目录与正文仍可用。

搜索优先精确 SQLSTATE,再匹配 condition / macro / 中文名称,最后匹配正文和已核消息模板。输入 40P0140p01 应返回同一条目。复用 OINK 本地搜索,先验证效果,确有缺口再做小范围增强。

保留 OINK 的移动导航、语言切换、目录、深浅色、复制代码、打印、Markdown 与 agent 输出。语言切换必须回到同一码;搜索和导出都不能携带未核研究笔记。独立站和子路径部署都要验证,不能依赖硬编码域名。

4. 范围、版本与身份模型

目录全集

主集合是范围内所有正式发布标签中由 PostgreSQL 定义的 SQLSTATE 并集,不只是最新 Appendix A。已删除的码保留条目,宏别名合并到同一码;条件名不是唯一主键,同一个条件名可能对应多个码。

所有 SQLSTATE 都是五位大写字符串,前导零必须保留。包括成功、警告与无数据状态,不能把它们全部描述成失败。范围外的扩展自定义码、任意用户 RAISE 码、客户端自定义码用方法页说明,不扩张为无穷条目。客户端/扩展复用核心码的行为可以作为该条目的补充路径。官方 Appendix A

优先解析 src/backend/utils/errcodes.txt,支持可选 condition 和一对多宏关系。旧版本若无该文件,改从当时的 src/include/utils/errcodes.h 与文档表提取并交叉校验。本轮已确认 PG 9.0.23 源码树采用后一种布局;文件不存在不能解释为“该版没有这些错误码”。

冻结来源与历史边界

每个采集来源记录 release、tag、commit SHA、文件路径、文件摘要、获取日期;预发行快照另加 channel。当前官方页面可见 PG 18.6 和 PG 19 Beta 3,但执行时应重新确认并锁定。PostgreSQL 文档版本入口

展示矩阵用每个大版本选定的发布快照;定义历史还要扫描范围内发布标签上的不同文件 blob,按 blob SHA 去重,避免漏掉补丁版新增或中途消失的码。具体补丁引入无法核实时只展示已证实范围。

版本记录至少区分:

  • present_in_snapshots:在哪些锁定快照中存在。
  • known_present_by:至少在某版已经存在,页面显示“该版或更早”。
  • introduced / removed:有发布边界证据时填写,允许多个存在区间。
  • changes:定义、命名、报文、触发条件、诊断字段和处理手段的变化,逐项附证据。
  • history_boundary / gaps:扫描下界、浅克隆限制、缺失标签与未证实部分。

同一码存在,不等于其语义、报文或解决方法在全部版本相同。正文以最新正式版为主,旧版本差异就近标注;不把 PG 15 新语法给 PG 10 读者当通用答案。

5. 内容与数据的职责

建议实施目录如下;这是目标布局,不表示本轮已创建这些产物。

err-code/
  PROJECT-PLAN.md
  CODEX-PROMPT.md
  references/                     原始参考材料,不作为站点内容
  hugo.yaml  go.mod  go.sum  Makefile
  content/docs/
    _index.md  _index.zh.md
    23505.md  23505.zh.md          所有码在这一层平铺
    40P01.md  40P01.zh.md
    codes/  classes/  common/  topics/  versions/  guides/
    coverage.md  coverage.zh.md
    methodology.md  methodology.zh.md
  sources/manifest.lock.json      冻结来源与工具版本
  raw/                            下载快照、原始目录与全量调用点候选
  evidence/<SQLSTATE>.json         核验过的路径、版本断言、引用与试验索引
  data/errcodes/<SQLSTATE>.json    由目录与 evidence 合成的规范事实
  data/classes.json
  data/versions.json
  schemas/                        少量必要的数据契约
  scripts/                        采集、合成、更新索引、检查、运行案例
  verify/cases/<SQLSTATE>/         setup / sessions / assertions / cleanup
  verify/results/                 环境清单、结构化结果与原始输出
  research/                       未核链接与问题清单,不发布
  reports/                        覆盖、进度、源资料变更、验收
  assets/  layouts/                确有必要的站点级定制
  static/data/                     派生的可下载公开数据

大型源码缓存不提交,公开内容只发布经过筛选的数据。采集数据与证据的最小快照应能从清单重建,并有摘要校验。常规 hugo 构建只读本地 Markdown、数据及已解析的主题依赖,不重新联网抓资料。

事实数据管理身份、别名、存在版本、消息变体、来源定位、验证记录。文章保存解释、诊断、处置和翻译。生成器只创建缺失页面、更新带明确标记的事实块与派生索引;已编辑的段落、场景和引用不被覆盖。首次确定自动区块边界后做一次重复生成无变化的检查。

front matter 保持精简:titledescriptionsqlstateslugtranslationKey、内容深度、审阅记录和翻译跟踪信息。共享事实从数据读取;如果为 Markdown 独立可读性镜像成表格或字段,必须能自动校验,不能形成第二真源。

证据应定位到具体断言,而不只写“source_grep”。至少可以沿着页面场景、消息变体或版本说明找到:哪个来源、哪个版本、哪个文件/章节、如何核验、有哪些限制。

6. 每个条目应该写到什么程度

固定核心锚点建议为 at-a-glancemeaningdiagnosisresponseversionsrelatedsources。适用时插入 messagesscenariosretryobservabilityclientsextensions。相同锚点在两种语言间保持稳定;不适用的可选章节不制造空壳。

核心阅读顺序:一句话解释 → 第一判断与处置 → 主要报文/触发条件 → 诊断与修复 → 复现和历史 → 参考证据。对定义但暂未证实使用的状态,明确说明检索范围和未知项,不编造现场。

深度 交付内容
stub 中间产物:身份、class、存在版本、权威来源;不能作为完整百科的交付终点
reference 每码的有效参考页:含义、适用上下文、诊断/处置或明确不适用说明、版本记录、相关码及来源
full 对代表性和常用码增加机制、实测场景、修复验证、重试边界、关键版本变化和必要客户端信息

另设审阅与验证维度:editorial_review 可以是 pending / reviewed,runtime_verification 可以是 passed / failed / not_run / not_applicable,并绑定具体版本、案例与证据。源码核验不能自动变成实测通过;编辑器也不能仅改状态字段就提高可信度。

第一组校准建议选择 12 个码:235052350340P014000142P01570145330028P012202E01000P0001XX000。它们分别覆盖约束、多会话、解析、取消、建连、别名、警告、自定义异常及默认内部错误。01000 等条目的优秀样本可以是短参考页,不能为了对齐篇幅而写成长文。

第二组以原 Tier 1 清单为候选,按使用价值和机制差异重新排序,并补充值得重点覆盖的新码,例如目录已确认的 25P04。清单是编辑优先级,不是“实际上会不会抛出”的证据,也不能限制最终目录全集。

英文是主稿,中文是完整对应版本;解释使用自然中文,官方条件名、API 标识和日志原文保留。中文摘要、版本说明、表格文字可翻译,执行 SQL 共用同一案例真源。翻译跟踪覆盖英文正文及可翻译元数据,不能只更新哈希而不更新译文。机器检查只证明结构与新旧关系,不能替代语义审阅。

7. 采集和事实核验

  1. 代码目录:解析冻结版本,保留原始行;对照该版本官方 Appendix A,解释宏行与文档行数量差异。
  2. 源码调用:扫描 src/backendsrc/plcontrib、相关接口和测试;直接调用、宏别名、辅助函数、默认错误码、变量赋值及转发分别记录。返回候选后再确认属于哪个报告调用,不能只取附近数行拼消息。
  3. 消息变体:保存原始格式串、errmsg / errdetail / errhint 的角色、同一调用组关系、路径与版本。处理多行字符串、errmsg_internal、复数、%m、条件组装等;不能自动解析时保留未解析候选。
  4. 机制与行为:官方文档给行为契约,源码给实现证据,回归/隔离/TAP 测试给可借鉴案例;.out 不能直接宣称是本项目已运行过的独立复现。
  5. 翻译报文:从对应版本与消息域的官方 PO 目录提取,核对非 fuzzy、非废弃、非空译文及占位符。PO 匹配只标“目录确认”,运行中文 locale 后才标“实测”;没有译文就展示英文,不造官方译文。
  6. 客户端:先建立常见驱动的公共取码/诊断指南,再对重点码核对类和常量。锁定驱动版本或 SHA;区分 exception class、constant、通用字段及无映射,避免逐页机械堆出九种驱动和多个 ORM。
  7. 补充阅读:优先官方文档、源码、发布说明与邮件原文。社区资料用于补充现场解释,不反过来覆盖版本事实。正式链接必须阅读并判断适用范围。

usage_evidence 只回答证据范围内的情况,例如运行观察到、源码路径已确认、仅确认目录定义、未知。不要设 ever_raised: false 这种横跨所有历史、扩展与用户函数的绝对断言。PL/pgSQL 支持用户指定 SQLSTATE,更说明这种断言范围过大。RAISE 文档

8. 复现与修复验证

一个案例应有稳定 ID、适用版本、权限与配置前提、准备、触发、预期诊断、修复、修复后断言和清理。页面中的可执行 SQL 与运行器共用这些案例;片段可以节选,但要链接到完整案例并标明前提。

场景类型 验证方式
单连接 DML/DDL 独立数据库或 schema,捕获结构化诊断,检查错误发生阶段与修复后的数据
事务状态 分别检查自动提交、显式事务、保存点/异常块,以及恢复后连接可用性
死锁、并发与序列化 多连接协调或 PostgreSQL isolation test 思路;明确同步条件和超时,不只依赖 sleep
认证与连接数 从建连阶段捕获异常,使用专用小实例及独立客户端;服务器未返回 SQLSTATE 时如实区分客户端错误
取消与超时 明确 statement timeout、lock timeout、取消请求、会话超时的触发者与不同后果
复制、FDW、配置 独立拓扑/配置案例,锁定组件版本;必要时做专项扩展批次
磁盘满、OOM、损坏与崩溃 不在用户实例或共享宿主制造故障;采用可控隔离实验或有范围的源码核验

运行器优先断言 SQLSTATE、必要诊断字段、事务/连接状态,以及修复是否成立;同时保存原始输出。预期报错的案例不能只看 psql 退出码,也不能把 ON_ERROR_STOP=0 后脚本跑完当通过。

报文模板与真实输出分开存。运行输出记录精确 server version、平台、locale、配置、客户端版本、容器镜像摘要或二进制来源。时间、PID 等可按明文规则规范化,但保留原始记录;不能把规范化后的文本伪装成原始日志。页中每个声称“实测”的块都必须能找到 run ID。

默认先在最新正式版跑代表案例,PG 10 上跑兼容的核心案例,对文章声称发生行为变化的版本跑边界对照。目录全版本覆盖不意味着运行全版本覆盖。中文 PO、历史码、资源故障等未实测部分分项报告,不能默认为通过。

人工 RAISE SQLSTATE '23505' 只能验证取码和捕获机制,不能证明已经复现唯一冲突;P0001 等条目自身讨论 RAISE 时例外。

9. 执行阶段与验收

阶段 主要交付 阶段完成依据
A:资料冻结与约定 当前文件保护记录、来源清单、版本边界、数据 schema、条目模板、执行日志 全部目标版本有来源或明确缺口;样例修订清单已形成
B:完整目录与最小站点 目录解析器、版本/别名数据、全量双语骨架、Oink 平铺路由、核心索引 去重集合等于来源并集,双语齐全,严格构建通过;此时只称目录骨架
C:代表样本闭环 12 个代表条目、案例运行器、23505 修订版、双语/证据/路由检查 有实际运行结果与不可运行项说明,样例暴露的模型问题已修正,能本地浏览
D:百科主体 按 class / 机制批次丰富所有条目,重点码做到 full,其余至少 reference 无伪完成的 stub,无通用套话代替具体含义;优先清单与未核问题可审计
E:历史与补充证据 定义变更、重要行为边界、条件翻译、驱动映射及定向阅读 关键版本断言可追溯,未知项如实披露,未核材料不进入发布输出
F:整体验收与交接 完整构建、桌面/移动/双语 QA、覆盖报告、操作说明、可达预览 所有必需检查成功;内容、来源、实测覆盖分别报告;下一步发布边界清楚

阶段 C 是技术校准检查点,通过后主动继续阶段 D;不要求用户每批批准。每批约 8–12 个相关码便于检查和回滚,不要求预先创建多份远程 PR。阶段 D 与 E 可按同一批交错执行,避免正文完成后才发现历史材料推翻解释。

建议命令契约:make fetch 显式刷新来源;make catalogue 提取;make generate 更新允许生成的部分;make check 跑离线数据/双语/证据/链接检查;make verify-smokemake verify 跑数据库案例;make build 严格构建;make serve 启动预览。初次依赖解析需要网络,此后普通内容构建不隐式刷新资料。

CI 将数据与构建、轻量运行验证、昂贵专项验证分开。正常检查不依赖实时搜索结果;外链检查区分失效与暂时不可达。解析器要用真实历史格式、别名、缺字段和版本边界编写有效测试,不用海量镜像实现的测试增加维护成本。

最终覆盖报告至少包含:每版定义数、SQLSTATE 并集数、宏别名数、实际条目数、EN/ZH 配对数、reference/full/stub 分布、待审条目、源码确认数、按版本成功/失败/跳过的案例数、来源缺口、翻译过期项、链接与构建结果。

“完整”指约定范围内全部定义已收录并有诚实可用的参考内容,重点条目有足够深度;不承诺证明一切源码路径或搜尽互联网。不能以“每个文件都存在”代替这个验收。

10. 本地可复用资产与实施边界

  • /Users/vonng/pgsty/oink:主题源码及当前 README;本轮观察到本地有未发布领先提交,执行时不能直接把工作树等同正式版本。
  • /Users/vonng/pgsty/oink-starter:最小配置来源,本轮 pin 为 v1.0.0;选择执行时可解析且验证通过的发行版并锁定。
  • /Users/vonng/pgcenter/waitevent:Docs 源文件映射到根路径、双语和证据报告的参考。
  • /Users/vonng/pgcenter/guc:旧版本提取和版本历史的参考。
  • /Users/vonng/pgcenter/.cache/postgresql:本轮可见 PG 13.23 至 18.6 的若干源码快照;目录名称不能代替摘要验证。
  • /Users/vonng/pgcenter/.cache/postgresql-git:有历史标签,但本轮确认是浅克隆,不能据此直接断言精确引入版本。

这些资产只读参考,不复制无关的完整站点,不修改兄弟目录。需要补齐 Git 历史就在项目自己的缓存中操作。/Users/vonng/pgcenter 本轮不是 Git 仓库,errorcode 是空目录;采用用户最后指定的 err-code,不移动或清理其他目录。

新会话的默认交付是本地完整项目、检查记录和预览。远程仓库、提交推送、PR、域名和正式发布不由原始材料中的 PR 节奏自动授权。域名未定不阻塞本地实现,配置使用可替换的开发基址。

执行入口见 CODEX-PROMPT.md