P0001 — raise_exception(引发异常)
速览
P0001 是 PostgreSQL 专用类别 P0(PL/pgSQL Error)中的 raise_exception 条件。不写条件名、也不写显式 SQLSTATE 的 RAISE EXCEPTION 会默认使用这个代码。报文由函数作者提供,因此 P0001 通常是应用或过程的控制信号,而不是某个服务器子系统的诊断。
严重级别和代码是两个选择。EXCEPTION 是 RAISE 的默认级别,通常会中止当前事务。NOTICE、WARNING、INFO、LOG 和 DEBUG 只按对应优先级生成消息;显式的 ERRCODE 也可以选择其他 SQLSTATE。读取时应始终同时记录严重级别和 SQLSTATE。
代表性案例 plpgsql_raise_exception 创建包含 RAISE EXCEPTION 'calibration exception' 的函数,调用它,再在同一自动提交连接上执行 SELECT 1。PostgreSQL 18.6 和 10.21 都返回 P0001、保留该报文,连接状态为 IDLE,并接受后续查询。下面的 SQL 摘录是共享注册表中的完整有序函数、调用和后续语句;实际运行中的模式限定函数名和清理由测试执行器统一管理。
| 字段 | 值 |
|---|---|
| SQLSTATE | P0001 |
| 条件名 | raise_exception |
| 状态 | 有效 |
| 已知存在于 | 8.0.0 |
| 锁定快照 | 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3 |
| 宏 | ERRCODE_RAISE_EXCEPTION |
| 别名 | — |
含义与触发路径
18.6 目录把 P0001 放在 PostgreSQL 专用的 P0 类 PL/pgSQL Error 中,并命名为 raise_exception。在 PL/pgSQL 执行器中,只有在未提供代码且级别不低于 ERROR 时才设置默认代码;之后执行器会报告调用方的报文,并附带可选的详细信息、提示和对象字段。
语法支持几条不同路径:
RAISE EXCEPTION 'message'默认使用P0001。RAISE EXCEPTION condition_name使用该条件自己的 SQLSTATE,因此不一定是P0001。RAISE EXCEPTION SQLSTATE '5-character-code'或RAISE ... USING ERRCODE = ...可以让过程暴露特定领域契约。除00000外,PostgreSQL 允许使用自选的五字符代码。- 较低级别的
RAISE WARNING 'message'只按该优先级送出消息。即使调用方显式选择了错误码,它也不是RAISE EXCEPTION的同一种事务事件。
无参数的 RAISE; 是活动异常处理器中的重新抛出控制。它的行为和 SQLSTATE 由正在重新抛出的异常决定,不是一次新的默认 P0001 事件。
报文与诊断
代表性注册表操作如下:
实际运行的函数名由测试执行器生成并带模式限定。18.6 观察到的诊断是:
P0001 没有统一的英文主报文,具体内容由函数提供。USING MESSAGE、DETAIL、HINT、COLUMN、CONSTRAINT、DATATYPE、TABLE 和 SCHEMA 可以添加结构化诊断。消息文本可以本地化而 SQLSTATE 保持不变,因此应按 P0001 分支,再读取结构化字段,不要解析主报文字符串。
诊断
先判断该代码是否来自有意的 RAISE EXCEPTION,还是函数显式选择了某个领域条件。记录 SQLSTATE、本地化和未本地化严重级别、主报文、详细信息、提示、上下文、源码位置以及调用函数的语句。在 PL/pgSQL 处理器中,SQLSTATE 和 SQLERRM 表示当前异常,GET STACKED DIAGNOSTICS 可以取出其字段。
随后定位函数分支及其事务上下文。自动提交下的失败调用只结束该语句,连接仍可执行下一条命令,代表性案例正是如此。显式事务中的调用通常会让事务进入中止状态,直到客户端执行 ROLLBACK 或回滚到保存点;服务器连接本身不一定终止。
EXCEPTION 子句会改变边界。受保护主体在子事务中运行;主体出错后,主体内对持久数据库状态的修改会先回滚,再执行第一个匹配的条件处理器,块外的修改仍保留。WHEN OTHERS 匹配除 QUERY_CANCELED 和 ASSERT_FAILURE 以外的所有错误,范围很宽,不能用它代替对目标 P0001 路径的识别。
处理
当过程确实要暴露通用的 PL/pgSQL RAISE 契约时使用 P0001。如果调用方需要区分校验、冲突、配额或其他业务结果,应选择并记录合适的 SQLSTATE,并补充便于处理的 DETAIL 或 HINT。不要为了简化应用代码就把无关的服务器错误都改成 P0001。
在客户端边界,显式事务需要先回滚后再执行无关命令;如果可以隔离函数调用,则使用保存点。在 PL/pgSQL 中,恢复逻辑明确时优先使用 WHEN raise_exception 或 WHEN SQLSTATE 'P0001' 这样的窄处理器。如果确实需要宽处理器,请先保存 RETURNED_SQLSTATE、MESSAGE_TEXT、PG_EXCEPTION_DETAIL、PG_EXCEPTION_HINT 和上下文,再决定继续还是重新抛出。
自然的 RAISE EXCEPTION 案例可以安全演示,因为它测试的正是预期的 PL/pgSQL 机制。这并不使 P0001 成为服务器故障证据;它是函数明确引发的异常。
版本
目录记录 P0001 存在于锁定的 8.0.0–8.4.22 pre-9.0 正式源码、9.0.23 至 18.6 的全部正式快照及 19 Beta 3 预览快照。同 tag 的 REL8_1_4 errcodes.sgml 表已经列出 P0001 和条件名 raise_exception,因此至少可以确认 8.1.4 已有该条件名。9.0 头文件视图中的类标题为 PL/pgSQL Error (PostgreSQL-specific error class),到 9.1 的文本定义变为 PL/pgSQL Error。7.0–7.3 仍有候选源码缺口;这些是目录观察边界,不是实现引入日期的断言。
18.6 固定源码 commit 为 724edf9bde9d356724ad384a2e196edc3c9f80f7。默认 RAISE EXCEPTION 规则有 PostgreSQL 18 文档和 18.6 执行器源码两方面依据。代表性案例在 PostgreSQL 18.6 和 10.21 上通过;它没有覆盖每一种自定义代码、处理器或事务模式。
相关
P0000 — plpgsql_error 是更宽的 PL/pgSQL 专用类条件。P0002 — no_data_found、P0003 — too_many_rows 和 P0004 — assert_failure 是独立的 P0 条件。25P02 — in_failed_sql_transaction 描述未处理异常中止显式事务后的后续状态。XX000 — internal_error 是服务器内部错误代码,不应作为有意 RAISE 的同义词。
来源
结构化证据记录在公开证据 JSON中。源码记录固定到 PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7;运行记录保留共享注册表、两个目标摘要和 P0001-snippet-registry-final-20260909 运行 ID。
src.errcodes.18.6—errcodes.txtsrc.pl-exec.18.6—pl_exec.cdoc.plpgsql.18— Errors and Messages 与 Error Trappingdoc.protocol.18— Error and Notice Message Fieldsdoc.transactions.18— Transactions