↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

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

百科 / SQL 状态码 / Class P0 PL/pgSQL 错误

P0004 assert_failure

ERROR 已实测 详解 实测通过

类别
Class P0 PL/pgSQL 错误
严重等级
ERROR
条件名
assert_failure
宏名称
ERRCODE_ASSERT_FAILURE
最早已知存在
9.5.0
状态
有效

版本覆盖

  1. 18
  2. 17
  3. 16
  4. 15
  5. 14
  1. 13
  2. 12
  3. 11
  4. 10
  5. 9.6
  6. 9.5
  7. 9.4
  8. 9.3
  9. 9.2
  10. 9.1
  11. 9.0
  1. 19 beta
  2. 20 dev

版本条依据已采样构建显示;灰色版本可能尚未采样,悬停可查看。手册链接随版本选择,源码和运行证据保持原核验构建。

速览

P0004 是 PL/pgSQL assert_failure。固定 ASSERT 执行路径确认它以 ERROR 报告,并按是否提供 message 选择错误文本;运行案例已在 PostgreSQL 18.6 和 10.21 上通过。

共享的 assertion_failure_recovery 案例已在 PostgreSQL 18.6 和 PostgreSQL 10.21 上通过。启用 plpgsql.check_asserts 后,失败的 ASSERT 返回 P0004 和 value must be positive,显式事务进入 INERROR;ROLLBACK 恢复为 IDLE,有效输入执行成功,关闭断言的对照调用返回零。

CREATE OR REPLACE FUNCTION p0004_assert(value integer) RETURNS integer LANGUAGE plpgsql AS $$ BEGIN ASSERT value > 0, 'value must be positive'; RETURN value; END $$;
SET plpgsql.check_asserts = on;
SHOW plpgsql.check_asserts;
BEGIN;
SELECT p0004_assert(0);
ROLLBACK;
SELECT p0004_assert(1);
SET plpgsql.check_asserts = off;
SHOW plpgsql.check_asserts;
SELECT p0004_assert(0);
SET plpgsql.check_asserts = on;
SHOW plpgsql.check_asserts;
SELECT p0004_assert(1);

含义

ASSERT 是 PL/pgSQL 中执行的不变量检查。PostgreSQL 计算其 Boolean 条件;结果为 false 或 NULL 时进入断言失败路径。固定执行器随后以 ERROR 和 SQLSTATE P0004 报告:只在进入该路径后计算 message 表达式,非 NULL 结果成为主报文,NULL 或省略 message 时使用 assertion failed。关闭检查时,条件和 message 表达式都会跳过。

plpgsql.check_asserts 是按会话生效的设置,用来控制是否检查 ASSERT。启用时,失败断言是真正的 ERROR,显式事务会进入 INERROR;关闭时 ASSERT 会被跳过,同一个 false 输入不能证明不变量成立,也不能替代生产环境的输入校验。

选定运行覆盖了带非 NULL message 的 false 条件,以及关闭检查时的 false 条件。NULL 条件和无 message 的回退文本是源码确认的语义,不是本批额外的自然运行观察。

报文模板

源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。

主消息 assertion failed
主消息 · alternate %s

来源: 来源:src/pl/plpgsql/src/pl_exec.c @ REL_18_6

诊断

先把 ErrorResponse 字段与服务器日志中的同一条记录对照。固定 18.6 路径的 message_primary 是计算后的 message 或 assertion failed;运行案例还记录了 ERROR、P0004、exec_stmt_assert,以及指向 PL/pgSQL 函数和 line 1 at ASSERT 的 context。要在出错的同一个会话执行 SHOW plpgsql.check_asserts,其他连接的设置不会影响它。

如果主报文是 assertion failed,检查 ASSERT 是否没有 message,或 message 表达式是否计算为 NULL。如果完全没有 P0004,先检查 SHOW plpgsql.check_asserts:关闭时会在计算条件前跳过检查。比较调用时要同时保留函数源码和会话设置;连接池中的另一个连接可能有不同设置,即使它们调用的是同一个函数。

区分程序不变量和预期业务输入。value > 0 这类 ASSERT 适合检查经过验证后本应永远成立的假设;预期的负数等业务输入应使用普通校验、约束或明确的应用错误。若错误发生在显式事务中,先检查事务状态再发送下一条命令:运行案例中事务在 ROLLBACK 前是 INERROR,并不是连接已经失效。

处置

显式事务中先执行 ROLLBACK,再以修正后的不变量或输入重现。共享案例验证了 ROLLBACK → IDLE、有效调用返回 1,以及把 plpgsql.check_asserts 设为 off 后同一个 false 输入不再报告断言。

如果 PL/pgSQL block 有意处理这个命名条件,可以使用 WHEN ASSERT_FAILURE。WHEN OTHERS 不会捕获 ASSERT_FAILURE,因此不能靠宽泛 handler 隐藏断言失败。异常块可以按文档规定的子事务边界恢复,但吞掉错误前必须检查不变量;关闭断言只是诊断对照,不是修复。

可复现案例

在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。

assertion_failure_recovery PG 10 / 18 有 SQL

前置条件

  • A disposable runner target has PL/pgSQL available.
  • plpgsql.check_asserts is explicitly enabled before the trigger.

触发

Call a PL/pgSQL function whose ASSERT condition is false inside an explicit transaction.

断言

  • The natural ASSERT failure has SQLSTATE P0004 and the expected diagnostic.
  • The failed explicit transaction is INERROR and ROLLBACK returns it to IDLE.
  • A valid call succeeds after rollback, and an explicit check_asserts=off control suppresses the assertion.
  • Re-enabling check_asserts makes the valid call succeed and the runner cleans up.

处置

Rollback the failed transaction, use a valid input, and keep assertions enabled for production behavior.

清理

Drop the case schema with an owner connection.

版本

锁定目录从 9.5.0 记录 P0004,并在列出的正式快照及 19beta3 中出现。固定执行器源码是 PostgreSQL 18.6 的 pl_exec.c#L3965-L3968。官方 PL/pgSQL 错误和消息文档说明 ASSERT 和命名条件;控制结构中的错误捕获文档定义 EXCEPTION 子事务及 handler 匹配边界。最新版本与 PG10 的运行案例确认了共享函数中的 P0004 和事务行为。

来源

证据

断言

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

运行记录

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

同类 SQL 状态码

状态码 条件名 宏名称 严重等级 版本
Class P0 PL/pgSQL 错误 PL/pgSQL Error 5 个 ↗
P0000 plpgsql_error ERRCODE_PLPGSQL_ERROR ERROR 8.0.0 起已知
PL/pgSQL 错误的类别项,核心未见直接调用。 有效
P0001 raise_exception ERRCODE_RAISE_EXCEPTION ERROR 8.0.0 起已知
RAISE EXCEPTION 未指定条件名或代码时的默认码。 有效
P0002 no_data_found ERRCODE_NO_DATA_FOUND ERROR 8.2.0 起已知
PL/pgSQL 中查询未取到所需的数据行。 有效
P0003 too_many_rows ERRCODE_TOO_MANY_ROWS ERROR 8.2.0 起已知
PL/pgSQL 中查询返回的行数多于预期。 有效
P0004 assert_failure ERRCODE_ASSERT_FAILURE ERROR 9.5.0 起已知
PL/pgSQL 的 ASSERT 断言条件不成立。 有效