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

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

百科 / 错误代码 / Class P0 PL/pgSQL错误

P0004 assert_failure

ERROR 已实测 详解 实测通过

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

版本覆盖

速览

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 返回 P0004value must be positive,显式事务进入 INERRORROLLBACK 恢复为 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;运行案例还记录了 ERRORP0004exec_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_FAILUREWHEN 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

同类错误代码

Class P0 PL/pgSQL错误 下的其他成员。