文档 / SQL 状态码 / Class P0 PL/pgSQL错误
P0001 raise_exception
引发异常
ERROR 已实测 详解 实测通过
- 条件名
raise_exception- 宏名称
ERRCODE_RAISE_EXCEPTION- 启用版本
- 8.0
- 状态
- 活跃
版本覆盖
速览
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 摘录是共享注册表中的完整有序函数、调用和后续语句;实际运行中的模式限定函数名和清理由测试执行器统一管理。
含义与触发路径
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 事件。
报文与诊断
代表性注册表操作如下:
CREATE FUNCTION raise_exception_case() RETURNS void
LANGUAGE plpgsql AS $$
BEGIN
RAISE EXCEPTION 'calibration exception';
END
$$;
SELECT raise_exception_case();
SELECT 1;
实际运行的函数名由测试执行器生成并带模式限定。18.6 观察到的诊断是:
SQLSTATE: P0001
severity: ERROR
message_primary: calibration exception
context: PL/pgSQL function ...raise_exception_case() line 3 at RAISE
source: pl_exec.c / exec_stmt_raise / line 3923
P0001 没有统一的英文主报文,具体内容由函数提供。USING MESSAGE、DETAIL、HINT、COLUMN、CONSTRAINT、DATATYPE、TABLE 和 SCHEMA 可以添加结构化诊断。消息文本可以本地化而 SQLSTATE 保持不变,因此应按 P0001 分支,再读取结构化字段,不要解析主报文字符串。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
caller-supplied RAISE format, condition, or MESSAGE expression
来源:src/pl/plpgsql/src/pl_exec.c(lines 3889-3923, exec_stmt_raise default and ereport) @ REL_18_6 · doc/src/sgml/plpgsql.sgml(lines 2815-2860, 2957-2968, 3768-3775, 3836-3858, 4008-4013) @ PG18-docs
适用范围:There is no universal P0001 primary text; the default message when no text is supplied is the condition name or SQLSTATE.
calibration exception
适用范围:This literal is specific to the representative function and is not a built-in P0001 message template.
诊断
先判断该代码是否来自有意的 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 成为服务器故障证据;它是函数明确引发的异常。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
plpgsql_raise_exception PG 10 / 18 有 SQL
前置条件
- PL/pgSQL is available
触发
Execute a function containing RAISE EXCEPTION without an explicit SQLSTATE.
断言
- SQLSTATE is P0001
- The custom message is preserved
- The failed call is isolated to its transaction
处置
Use a domain-specific SQLSTATE only when the caller contract requires it; catch and handle the exception at the correct transaction boundary.
清理
Drop the function and case schema.
版本
目录记录 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 上通过;它没有覆盖每一种自定义代码、处理器或事务模式。
来源
- 上游源码 doc/src/sgml/errcodes.sgml 第 1303–1308 行
- 核验材料 verify/cases/P0001/cases.json
- 核验材料 doc/src/sgml/plpgsql.sgml
- 核验材料 doc/src/sgml/protocol.sgml
- 核验材料 doc/src/sgml/xact.sgml
- 核验材料 sources/manifest.lock.json
- 核验材料 verify/cases/P0001/snippets.json
- 核验材料 src/backend/utils/errcodes.txt
- 核验材料 src/pl/plpgsql/src/pl_exec.c 第 3889–3923 行
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
P0001 is the raise_exception condition in PostgreSQL-specific Class P0, PL/pgSQL Error.
-
A RAISE EXCEPTION with no condition name and no SQLSTATE defaults to raise_exception, P0001.
-
RAISE supports DEBUG, LOG, INFO, NOTICE, WARNING, and EXCEPTION levels; EXCEPTION normally aborts the current transaction, while lower levels generate messages, and USING can supply structured fields.
-
A PL/pgSQL block with an EXCEPTION clause runs its protected body in a subtransaction; persistent changes made by the body are rolled back before the matching handler runs.
-
OTHERS matches every error type except QUERY_CANCELED and ASSERT_FAILURE, and a new error raised by the selected handler is not caught by that same clause.
-
Inside an exception handler, SQLSTATE and SQLERRM identify the active exception and GET STACKED DIAGNOSTICS can retrieve its fields.
-
plpgsql_raise_exception returned P0001 with the caller-supplied calibration exception message on PostgreSQL 18.6 and 10.21; both autocommit connections remained IDLE and accepted SELECT 1.
-
An unhandled EXCEPTION in an explicit transaction normally requires rollback before unrelated commands, while the representative autocommit call leaves the connection usable.
-
The locked catalogue records P0001 in the 8.0.0–8.4.22 pre-9.0 formal sources, every listed formal snapshot from 9.0.23 through 18.6, and 19beta3. The same-tag REL8_1_4 errcodes.sgml row already lists P0001 as raise_exception, confirming that condition-name observation by 8.1.4. The class title changes between the 9.0 header and 9.1 text definitions; candidate source gaps remain for 7.0–7.3. These are presence boundaries, not asserted implementation introduction dates.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | plpgsql_raise_exception |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | plpgsql_raise_exception |
同类 SQL 状态码
| 状态码 | 条件名 | 宏名称 | 严重等级 | 版本 |
|---|---|---|---|---|
| P0000 | plpgsql_error | ERRCODE_PLPGSQL_ERROR |
ERROR | 8.0 |
| PL/pgSQL 错误的类别项,核心未见直接调用。 | 活跃 | |||
| P0001 | raise_exception | ERRCODE_RAISE_EXCEPTION |
ERROR | 8.0 |
| RAISE EXCEPTION 未指定条件名或代码时的默认码。 | 活跃 | |||
| P0002 | no_data_found | ERRCODE_NO_DATA_FOUND |
ERROR | 8.2 |
| PL/pgSQL 中查询未取到所需的数据行。 | 活跃 | |||
| P0003 | too_many_rows | ERRCODE_TOO_MANY_ROWS |
ERROR | 8.2 |
| PL/pgSQL 中查询返回的行数多于预期。 | 活跃 | |||
| P0004 | assert_failure | ERRCODE_ASSERT_FAILURE |
ERROR | 9.5 |
| PL/pgSQL 的 ASSERT 断言条件不成立。 | 活跃 | |||