选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

文档 / SQL 状态码 / Class P0 PL/pgSQL错误

P0001 raise_exception

引发异常

ERROR 已实测 详解 实测通过

类别
Class P0 PL/pgSQL错误
严重等级
ERROR
条件名
raise_exception
宏名称
ERRCODE_RAISE_EXCEPTION
启用版本
8.0
状态
活跃

版本覆盖

速览

P0001 是 PostgreSQL 专用类别 P0(PL/pgSQL Error)中的 raise_exception 条件。不写条件名、也不写显式 SQLSTATE 的 RAISE EXCEPTION 会默认使用这个代码。报文由函数作者提供,因此 P0001 通常是应用或过程的控制信号,而不是某个服务器子系统的诊断。

严重级别和代码是两个选择。EXCEPTIONRAISE 的默认级别,通常会中止当前事务。NOTICEWARNINGINFOLOGDEBUG 只按对应优先级生成消息;显式的 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 MESSAGEDETAILHINTCOLUMNCONSTRAINTDATATYPETABLESCHEMA 可以添加结构化诊断。消息文本可以本地化而 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 处理器中,SQLSTATESQLERRM 表示当前异常,GET STACKED DIAGNOSTICS 可以取出其字段。

随后定位函数分支及其事务上下文。自动提交下的失败调用只结束该语句,连接仍可执行下一条命令,代表性案例正是如此。显式事务中的调用通常会让事务进入中止状态,直到客户端执行 ROLLBACK 或回滚到保存点;服务器连接本身不一定终止。

EXCEPTION 子句会改变边界。受保护主体在子事务中运行;主体出错后,主体内对持久数据库状态的修改会先回滚,再执行第一个匹配的条件处理器,块外的修改仍保留。WHEN OTHERS 匹配除 QUERY_CANCELEDASSERT_FAILURE 以外的所有错误,范围很宽,不能用它代替对目标 P0001 路径的识别。

处理

当过程确实要暴露通用的 PL/pgSQL RAISE 契约时使用 P0001。如果调用方需要区分校验、冲突、配额或其他业务结果,应选择并记录合适的 SQLSTATE,并补充便于处理的 DETAILHINT。不要为了简化应用代码就把无关的服务器错误都改成 P0001

在客户端边界,显式事务需要先回滚后再执行无关命令;如果可以隔离函数调用,则使用保存点。在 PL/pgSQL 中,恢复逻辑明确时优先使用 WHEN raise_exceptionWHEN SQLSTATE 'P0001' 这样的窄处理器。如果确实需要宽处理器,请先保存 RETURNED_SQLSTATEMESSAGE_TEXTPG_EXCEPTION_DETAILPG_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 上通过;它没有覆盖每一种自定义代码、处理器或事务模式。

来源

证据

断言

每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。

运行记录

目标服务器版本结果覆盖案例
latest 18.6 (Homebrew) passed plpgsql_raise_exception
pg10 10.21 (Debian 10.21-1.pgdg90+1) passed plpgsql_raise_exception

同类 SQL 状态码

状态码 条件名 宏名称 严重等级 版本
Class P0 PL/pgSQL错误 PL/pgSQL Error 5 个
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 断言条件不成立。 活跃