23505 — unique_violation:唯一性冲突
行或索引违反唯一约束,常见于重复键插入。
英文手册覆盖始于 PostgreSQL 8.1. 来源历史与运行验证各自保留独立版本边界。
当前阅读 PG 18·选择有来源记录的版本
- aliases
- 未知
- class name
- Integrity Constraint Violation
- condition name
- unique_violation
- lang
- en
- sqlstate
- 23505
版本定义 PG 18
速览 {#at-a-glance}
23505 是 PostgreSQL 的 unique_violation 条件。当行、索引构建或逻辑应用发现某个值不能与正在执行的唯一性约束共存时,就会产生这个状态码。
第一步应保存完整的 ErrorResponse 以及失败的语句。最有用的字段是 C(SQLSTATE)、M(主消息)、D(detail),以及在服务器提供时的 s(schema)、t(table)和 n(constraint 或 index)。在 psycopg 中,这些字段位于 exc.sqlstate 和 exc.diag。对象字段属于线协议;它们不是 CSV 日志的标准列名,也不是 JSON 日志的标准键名。
恢复方式取决于错误发生的位置:
- 自动提交语句失败,但连接可以继续接收下一条命令。
- 显式事务中的语句失败后,事务进入中止状态。必须回滚整个事务,或回滚到保存点,然后才能继续发语句;否则 PostgreSQL 会返回
25P02。 - 延迟唯一约束可以暂时接受重复行,并在
COMMIT时报告23505。 - PL/pgSQL 的
EXCEPTION块可以在子事务中捕获该冲突,但处理器必须足够窄,能够确认究竟是哪一个操作失败。
当前选定的公开运行记录按案例和目标覆盖 PostgreSQL 18.6 的 12 个独立通过案例,以及 PostgreSQL 10.21 的 11 个通过案例;NULLS NOT DISTINCT 在 PG10 标为不适用。完整运行仍为未被替代案例的来源;定向最终记录分别选择 DML 诊断、精确的 log_fields 关联、registry 片段和手动事务边界,不重复或覆盖这些案例。另有 PG14.24/PG15.19 的版本边界对照:PG14 的显式 UNIQUE NULLS NOT DISTINCT 只得到不支持语法的 42601,PG15 则在第二个 NULL 上实际得到 23505;该对照不计入上述基础数量。选定 run ID 和结构化观察保存在公开证据 JSON中;被替代的 summary 与原始 JSONL 仅保留为本地审计数据。
上面的生成锁定快照表示目录定义文件的版本覆盖。本页的可执行兼容性目标是 PostgreSQL 18.6 和 10.21;目录条目不声称 23505 是 PostgreSQL 10 才引入的。
含义与触发路径 {#meaning}
SQLSTATE 目录把 23505 放在 Class 23 integrity_constraint_violation 下,条件名为 unique_violation。在普通 btree 路径中,PostgreSQL 检查索引项;如果冲突的已提交键或并发插入键不符合索引语义允许的条件,就会报告错误。主键也是唯一索引,因此重复主键值同样使用这个状态码。
同一个 SQLSTATE 可以描述多种机制:
- 违反 DML 唯一约束或索引。
INSERT,以及改变键值的UPDATE,都可能与唯一索引保护的已有行冲突。普通消息模板是duplicate key value violates unique constraint "...",可选的 detail 是Key (...)=(...) already exists.。 - 构建唯一索引。 在已有重复行的表上构建唯一索引时使用另一套模板:
could not create unique index "...",detail 为Key (...)=(...) is duplicated.。这是索引构建失败,不是普通行插入消息。 - 延迟约束。 使用
DEFERRABLE INITIALLY DEFERRED时,重复值可以留在事务中,直到提交时检查约束。因此错误对应COMMIT,失败的顶层提交会回滚该事务。 - 逻辑复制应用。 PostgreSQL 18 会把应用冲突分类为
insert_exists等;冲突报告器仍将相关的 insert、update 和 multiple-unique 路径映射到23505。其消息形态和服务器日志上下文与客户端 btree 插入不同。本页有该路径的源码和文档证据,但当前运行批次没有建立 publisher/subscriber 拓扑。
状态码说明了条件所属的类别,但不能单独说明冲突是持久的业务重复、键选择竞态,还是维护操作失败。需要结合语句、schema、约束定义、事务上下文和并发活动作出判断。
下面的 SQL 代码块是与指定案例同一操作的说明性片段。权威可执行来源是 scripts/verify_cases.py 和 verify/cases/23505/cases.json;片段只省略临时 schema 命名和清理,并标明案例 ID,不构成第二套可运行案例定义。
报文与诊断字段 {#messages}
在 PostgreSQL 18.6 源码的 nbtinsert.c 普通路径中,服务器调用 BuildIndexValueDescription,报告唯一性错误,并附加表和约束身份。一次真实运行记录如下:
SQLSTATE: 23505
severity: ERROR
message_primary: duplicate key value violates unique constraint "users_email_key"
message_detail: Key (email)=(a@example.test) already exists.
schema_name: c23505_dml_unique_conflict
table_name: users
constraint_name: users_email_key
source: nbtinsert.c / _bt_check_unique
detail 不是必然存在的。如果调用者没有权限查看相关列,行级安全策略阻止描述,或者索引是表达式索引,PostgreSQL 可能省略键值。相同运行中的 INSERT-only 角色仍得到 SQLSTATE 和对象身份,但没有 message_detail。
协议字段定义在 Error and Notice Message Fields 中。应从驱动异常读取这些字段,不要从日志解析器推断。18.6 的日志配置文档描述了 CSV 的 sql_state_code、message、detail 等字段,以及 JSON 的 state_code、message、detail 等键;两种格式都没有把协议中的 constraint_name 定义为标准日志字段。定向 log_fields run 按同一后端 PID、模式/表、约束、主消息和 detail 将 collector 记录与驱动诊断逐项匹配:PostgreSQL 18.6 同时得到 CSV 和 JSON,PostgreSQL 10.21 得到 CSV。
索引构建报文明确不同:
SQLSTATE: 23505
message_primary: could not create unique index "idx_concurrent"
message_detail: Key (email)=(dup) is duplicated.
source: tuplesortvariants.c / comparetup_index_btree_tiebreak
不要只解析英文报文来分类错误。应先按 SQLSTATE 分支,再使用结构化字段和操作上下文。消息文本可能随本地化变化,而五字符 SQLSTATE 是稳定的线协议值。
诊断 {#diagnosis}
记录失败语句、SQLSTATE、主消息、detail、hint、schema/table/constraint 字段、服务器版本和事务状态。驱动应保留原始异常;通用 ORM 错误字符串可能丢掉定位冲突对象所需的字段。
针对某个表,在修改数据前同时检查约束和索引。下面两条查询就是运行器使用的 diagnostic_catalog_queries;隔离运行会对其 accounts 表实际执行:
SELECT conname, contype, condeferrable, condeferred,
pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid = 'accounts'::regclass;
SELECT indexrelid::regclass AS index_name,
indisunique, indisvalid, indisready, indislive,
pg_get_indexdef(indexrelid)
FROM pg_index
WHERE indrelid = 'accounts'::regclass;
对于普通 DML 错误,将尝试写入的键与命名约束保护的行进行比较。检查该表上的每一项唯一性约束;语句指定了一个冲突目标,也仍可能违反另一个唯一约束。对于索引构建错误,在重试前找出重复键,并在并发构建失败后检查 pg_index。
运行案例 concurrent_unique_conflict 使用两个会话和一个观察会话。会话 A 持有未提交的 token='raced';在 A 提交前,观察会话看到 B 的语句 wait_event_type=Lock、wait_event=transactionid。A 提交后,B 收到 23505,并在回滚前处于 INERROR。这个同步条件证明了事件顺序;固定 sleep 不能提供同等证据。
处置与修复 {#response}
先恢复事务(案例:explicit_tx_abort_recovery、savepoint_recovery)
启用自动提交时,失败操作已经结束,运行案例中的连接状态为 IDLE。应用应先决定如何处理输入,再发起下一条命令。
在显式事务中,第一次失败后不要继续使用该连接,先处理失败事务:
下面的 INSERT INTO items VALUES (3, 'seed') 是真实的重复键触发;后面的 ROLLBACK 是必须的恢复操作。
CREATE TABLE items(id integer PRIMARY KEY, note text UNIQUE NOT NULL);
INSERT INTO items VALUES (1, 'seed');
BEGIN;
INSERT INTO items VALUES (2, 'outer');
INSERT INTO items VALUES (3, 'seed');
ROLLBACK;
BEGIN;
INSERT INTO items VALUES (2, 'after rollback');
COMMIT;
如果只有一小段工作是可选的,可以使用保存点保留外层工作:
保存点之后的插入复用了已经准备好的唯一值,因此是真实的 23505 触发;ROLLBACK TO SAVEPOINT 只撤销这段失败的子事务。
CREATE TABLE items(id integer PRIMARY KEY, note text UNIQUE NOT NULL);
INSERT INTO items VALUES (1, 'seed');
BEGIN;
INSERT INTO items VALUES (2, 'outer');
SAVEPOINT unique_case;
INSERT INTO items VALUES (3, 'seed');
-- 事务失败时,这条语句预期返回 25P02。
SELECT count(*) FROM items;
ROLLBACK TO SAVEPOINT unique_case;
INSERT INTO items VALUES (3, 'after savepoint');
RELEASE SAVEPOINT unique_case;
COMMIT;
运行器在回滚前执行 SELECT 时观察到 25P02,在 ROLLBACK TO SAVEPOINT 后观察到 INTRANS。普通 ROLLBACK 会让显式事务回到 IDLE;ROLLBACK TO 会保留保存点之前的工作。
延迟约束会改变错误发生的阶段(案例:deferred_commit_conflict)。在真实案例中,两次重复插入在连接处于 INTRANS 时都成功;随后 COMMIT 报 23505,连接回到 IDLE,失败顶层事务产生的行数为零。应在提交前修复键,或回滚并重试整个工作单元。
PL/pgSQL 可以在异常块中处理自然产生的唯一性冲突(案例:plpgsql_exception_recovery):
CREATE TABLE items(id integer PRIMARY KEY, note text);
INSERT INTO items(id, note) VALUES (1, 'seed');
CREATE FUNCTION try_insert(wanted integer) RETURNS text
LANGUAGE plpgsql AS $$
DECLARE returned_state text;
BEGIN
INSERT INTO items(id, note) VALUES (wanted, 'body');
RETURN 'inserted';
EXCEPTION WHEN unique_violation THEN
GET STACKED DIAGNOSTICS returned_state = RETURNED_SQLSTATE;
INSERT INTO items(id, note) VALUES (wanted + 1, 'handler');
RETURN returned_state;
END
$$;
SELECT try_insert(1);
受保护的代码块具有子事务行为。发生错误时,该代码块内部已经写入的持久化改动会在处理器运行前回滚;进入代码块之前的改动仍会保留。异常块应保持窄范围:如果其中有多条可能违反不同唯一约束的语句,那么捕获到 unique_violation 本身不能证明是哪一条操作造成了它。PostgreSQL 的 PL/pgSQL 文档也针对通用 upsert 处理器提醒了这一点。
选择符合业务语义的操作(案例:on_conflict_target_scope)
ON CONFLICT 用于表达明确的冲突策略,不是隐藏所有重复行的通用指令。冲突目标决定 arbiter。在运行案例中,已有行占用了 phone='phone-1':
CREATE TABLE accounts(
id integer PRIMARY KEY,
email text NOT NULL,
phone text NOT NULL,
CONSTRAINT accounts_email_uq UNIQUE (email),
CONSTRAINT accounts_phone_uq UNIQUE (phone)
);
INSERT INTO accounts VALUES (1, 'existing@example.test', 'phone-1');
INSERT INTO accounts(id,email,phone)
VALUES (2, 'existing@example.test', 'phone-2')
ON CONFLICT (email) DO NOTHING;
-- 只处理 email 冲突。仅 phone 冲突时仍会产生 23505。
INSERT INTO accounts(id,email,phone)
VALUES (3, 'new@example.test', 'phone-1')
ON CONFLICT (email) DO NOTHING;
-- 省略 target 时,DO NOTHING 覆盖任一可用 arbiter 的冲突。
INSERT INTO accounts(id,email,phone)
VALUES (4, 'third@example.test', 'phone-1')
ON CONFLICT DO NOTHING;
对于 DO UPDATE,应确保更新是确定性的,并检查其业务结果。对于幂等键,应将传入请求的相关身份和参数与已存请求比较,再核对已有业务结果,然后才能返回“已经处理”。仅发生幂等键碰撞,不能证明先前请求等价。
谨慎修复序列(案例:sequence_lag_repair)
手动指定键可能使序列落后于表。受控运行案例使用了非默认序列:
下面第二个使用 nextval 的插入是真实的重复键触发;setval 后又执行了一次真实插入,以验证修复后的下一个值。
CREATE SEQUENCE ids_seq START WITH 100 INCREMENT BY 7 MINVALUE 100 MAXVALUE 100000;
CREATE TABLE items(id integer PRIMARY KEY, note text);
INSERT INTO items(id,note) VALUES (100, 'explicit');
INSERT INTO items(id,note) VALUES (nextval('ids_seq'), 'generated');
SELECT setval('ids_seq', (SELECT max(id) FROM items), true);
INSERT INTO items(id,note) VALUES (nextval('ids_seq'), 'after repair');
受控 setval 后下一值为 107。这种修复有明确前提:暂停写入者,确认序列身份和所有关系,空表不能传入无效值,并检查 increment、边界、cache 和 is_called。setval 不是通用的并发修复;序列变更也不会像普通表写入那样回滚。
只有在操作可重试时才重试
序列化失败处理文档 说明了某些并发选择键的场景可能以 23505 呈现。应用确认属于这种语义后,应重试完整事务(包括选择键的逻辑),并配合有界退避和幂等策略。不要盲目重试:用户明确请求的重复可能是永久条件,反复尝试也可能得到同一冲突。
双会话案例证明了锁顺序建立后会出现冲突,但运行器没有声称所有相同状态码的业务操作都可以安全重试。
处理并发索引构建失败(案例:index_build_conflict)
CREATE INDEX 文档 说明,如果并发构建的扫描遇到唯一性失败等问题,可能留下 INVALID 索引。在本次重复扫描案例中,pg_index 显示 indisvalid=false、indisready=false、indislive=true、indisunique=true;普通事务性构建回滚后没有留下索引。解决重复数据后检查实际目录状态,适当时删除遗留的无效索引,再重新构建。不要把这一状态推广到 CREATE INDEX CONCURRENTLY 的所有失败阶段。
版本与边界 {#versions}
PostgreSQL 10.21 和 18.6 都实际观察到了相同 SQLSTATE。两版源码行号和内部函数名不同;兼容性判断应使用 SQLSTATE 与操作上下文,而不是使用源码行号。
UNIQUE NULLS NOT DISTINCT 在 PostgreSQL 15 及以后可用,且必须显式选择。运行案例向默认唯一列插入两个 NULL 成功;向单独声明的 UNIQUE NULLS NOT DISTINCT 约束插入第二个 NULL 时产生 23505。升级不会默默把旧约束的默认语义改成 NULLS NOT DISTINCT。
单独的版本边界对照已经实际记录了可用性和行为:PostgreSQL 14.24 接受普通唯一列的两个 NULL,但显式声明因 42601 拒绝且没有 23505;PostgreSQL 15.19 在显式约束的第二个 NULL 上产生 23505,自动提交会话保持 IDLE,并成功提交有效值修复。这些记录单独保留,不增加基础选定案例数量。在其他临时目标上执行时,应先检查版本并按分支运行:先执行 ordinary_create、ordinary_first、ordinary_second、ordinary_verify,再执行 explicit_create;如果得到 PG14 预期的 42601,就在这里停止,不要发送 explicit_first、explicit_second、explicit_repair 或 explicit_verify。只有 explicit_create 在 PG15 或更高版本成功后,才继续显式插入、观察第二个 NULL 的结果,再执行修复和验证。
-- ordinary_create
CREATE TABLE ordinary_nulls (external_id integer UNIQUE);
-- ordinary_first
INSERT INTO ordinary_nulls VALUES (NULL);
-- ordinary_second
INSERT INTO ordinary_nulls VALUES (NULL);
-- ordinary_verify
SELECT count(*) FROM ordinary_nulls;
-- explicit_create
CREATE TABLE explicit_nulls (external_id integer, CONSTRAINT nulls_not_distinct_uq UNIQUE NULLS NOT DISTINCT (external_id));
-- explicit_first
INSERT INTO explicit_nulls VALUES (NULL);
-- explicit_second
INSERT INTO explicit_nulls VALUES (NULL);
-- explicit_repair
INSERT INTO explicit_nulls VALUES (1);
-- explicit_verify
SELECT count(*) FROM explicit_nulls;
PostgreSQL 18 的逻辑冲突报告器使用 insert_exists 等标签。消息改变并不意味着相关唯一冲突换成了别的 SQLSTATE。本批证据来自源码和文档;运行报告没有声称测试了复制拓扑。
锁定目录在 PostgreSQL 7.4 的定义中已观察到 23505,并持续到 8.4.22 的 pre-9.0 定义;随后在列出的所有正式快照直到 PostgreSQL 18.6 以及 PostgreSQL 19 Beta 3 预览中存在。这是 definition_only 的存在边界,不是确切实现引入版本或运行时使用断言。
相关代码 {#related}
25P02— in_failed_sql_transaction 说明显式事务中未处理语句失败后的后续错误。40001— serialization_failure 与40P01— deadlock_detected 是主要的事务重试相关错误;PostgreSQL 也记录了特定的23505键选择竞态。23503— foreign_key_violation 也是 Class 23 完整性错误,但缺少被引用行的诊断和修复步骤不同。
来源与证据 {#sources}
本页使用的证据 ID 是公开证据 JSON中的 identity.class-and-condition、runtime.dml-template、runtime.protocol-fields、runtime.index-build-template、runtime.logical-apply-sqlstate、runtime.tx-contexts、runtime.retry-boundary、runtime.on-conflict-scope、runtime.sequence-repair-limit、runtime.nulls-choice、runtime.detail-visibility 和 runtime.version-boundary。选定的运行记录对未替代案例使用完整运行,对 DML 使用 23505-diagnostic-snippet-20260909,对精确 collector 关联使用 23505-log-fields-final-20260909,对 registry 片段使用 23505-snippet-contract-20260909,对显式事务和保存点恢复使用 manual-boundary run。单独的边界记录是 runtime.23505-boundary-pg14-20260909.pg14 和 runtime.23505-boundary-pg15-20260909.pg15,用于版本对照,不增加基础案例数量。被替代的完整运行选择仅保留为本地审计数据。
- 固定源码提交中的 PostgreSQL 18.6
errcodes.txt—— Class 23 与unique_violation身份。 - 固定源码提交中的 PostgreSQL 18.6 nbtree 唯一性检查 —— DML 报文与协议对象字段。
- 固定源码提交中的 PostgreSQL 18.6 索引值描述 —— detail 可见性限制。
- 固定源码提交中的 PostgreSQL 18.6 索引构建错误 —— 独立的构建报文模板。
- 固定源码提交中的 PostgreSQL 18.6 逻辑冲突报告器 —— 应用标签和 SQLSTATE 映射。
- INSERT 命令参考 —— 冲突目标范围和 arbiter 限制。
- CREATE INDEX 命令参考 —— 并发构建阶段和无效索引行为。
- Error and Notice Message Fields 与 服务器日志配置 —— 协议字段与 collector 字段的区别。
- PL/pgSQL 控制结构、事务教程 和序列函数 —— 恢复与受控修复语义。
比较版本
SQLSTATE 证据与已记录的运行版本
cases · dml_unique_conflict
{
"assertions": [
"SQLSTATE is 23505",
"Protocol diagnostics identify the schema, table, and constraint",
"A successful autocommit connection is IDLE after the error"
],
"case_id": "dml_unique_conflict",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 0,
"preconditions": [
"A disposable database or schema",
"One NOT DEFERRABLE unique constraint"
],
"repair": "Choose a valid key or change the business operation; do not discard the collision implicitly.",
"trigger": "Insert a second row with the same email value.",
"versions": [
"10",
"18"
]
}cases · explicit_tx_abort_recovery
{
"assertions": [
"The failed transaction is INERROR",
"The next statement gets 25P02",
"ROLLBACK restores a usable connection"
],
"case_id": "explicit_tx_abort_recovery",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 1,
"preconditions": [
"An explicit transaction",
"One unique constraint"
],
"repair": "ROLLBACK the transaction, then retry a deliberate valid operation.",
"trigger": "Cause 23505 after BEGIN, then issue a statement before rollback.",
"versions": [
"10",
"18"
]
}cases · savepoint_recovery
{
"assertions": [
"The failed subtransaction is INERROR",
"ROLLBACK TO SAVEPOINT restores INTRANS",
"The outer change and post-savepoint repair both commit"
],
"case_id": "savepoint_recovery",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 2,
"preconditions": [
"An explicit transaction and SAVEPOINT",
"One unique constraint"
],
"repair": "ROLLBACK TO the savepoint and continue with a valid operation.",
"trigger": "Cause 23505 after a savepoint while an outer change is pending.",
"versions": [
"10",
"18"
]
}cases · deferred_commit_conflict
{
"assertions": [
"The inserts are accepted before COMMIT",
"COMMIT raises 23505",
"The failed top-level transaction returns to IDLE and its rows are rolled back"
],
"case_id": "deferred_commit_conflict",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": false,
"position": 3,
"preconditions": [
"A DEFERRABLE INITIALLY DEFERRED unique constraint",
"Two duplicate rows in one transaction"
],
"repair": "Make keys unique before COMMIT or roll back and retry the whole transaction.",
"trigger": "Insert both rows successfully and commit.",
"versions": [
"10",
"18"
]
}cases · plpgsql_exception_recovery
{
"assertions": [
"GET STACKED DIAGNOSTICS reports 23505",
"The surrounding call succeeds",
"The handler's repair row commits"
],
"case_id": "plpgsql_exception_recovery",
"cleanup": "Drop the function and case schema with an owner connection.",
"has_snippet": true,
"position": 4,
"preconditions": [
"PL/pgSQL language",
"A function that catches unique_violation"
],
"repair": "Use a narrowly scoped EXCEPTION handler and verify which statement caused the violation.",
"trigger": "A natural duplicate insert inside the function.",
"versions": [
"10",
"18"
]
}cases · concurrent_unique_conflict
{
"assertions": [
"B is observed waiting on a lock before A commits",
"B receives 23505 after A commits",
"B is INERROR until rollback and exactly one row remains"
],
"case_id": "concurrent_unique_conflict",
"cleanup": "Roll back both workers if needed, then drop the case schema.",
"has_snippet": false,
"position": 5,
"preconditions": [
"Two sessions",
"A unique index",
"An observer session reading pg_stat_activity"
],
"repair": "Coordinate key allocation or retry the complete transaction when the business operation is retryable.",
"trigger": "Session A holds an uncommitted key while session B inserts the same key.",
"versions": [
"10",
"18"
]
}cases · on_conflict_target_scope
{
"assertions": [
"The targeted email clause does not suppress a phone collision",
"An omitted-target DO NOTHING handles a usable unique conflict",
"The result is checked against the intended business policy"
],
"case_id": "on_conflict_target_scope",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 6,
"preconditions": [
"Separate unique email and phone constraints",
"A pre-existing phone value"
],
"repair": "Select the conflict target and DO UPDATE/DO NOTHING policy to match the business invariant; reconcile idempotency requests with the original request and result.",
"trigger": "Use ON CONFLICT (email) for a row that collides only on phone.",
"versions": [
"10",
"18"
]
}cases · nulls_not_distinct
{
"assertions": [
"The second NULL raises 23505",
"The diagnostic identifies the explicit constraint",
"The behavior is not attributed to an upgrade changing the old default"
],
"case_id": "nulls_not_distinct",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": false,
"position": 7,
"preconditions": [
"PostgreSQL 15 or later",
"UNIQUE NULLS NOT DISTINCT is explicitly declared"
],
"repair": "Choose NULLS DISTINCT (the default) or NULLS NOT DISTINCT deliberately for the invariant.",
"trigger": "Insert a second NULL into the explicit NULLS NOT DISTINCT constraint.",
"versions": [
"15",
"16",
"17",
"18"
]
}cases · nulls_not_distinct_version_boundary
{
"assertions": [
"Ordinary UNIQUE accepts two NULLs on both targets",
"PG14 records the actual unsupported syntax diagnostic",
"PG15 records a natural 23505 for the explicit second NULL and a valid repair"
],
"case_id": "nulls_not_distinct_version_boundary",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 8,
"preconditions": [
"A disposable PostgreSQL 14 or 15 target",
"One ordinary UNIQUE and one explicit UNIQUE NULLS NOT DISTINCT declaration"
],
"repair": "Use the explicit NULL policy deliberately; after the supported duplicate, insert a valid non-duplicate value and verify the connection remains usable.",
"trigger": "Insert two NULLs under ordinary UNIQUE, then execute the explicit NULLS NOT DISTINCT declaration and, where supported, a second NULL.",
"versions": [
"14",
"15"
]
}cases · sequence_lag_repair
{
"assertions": [
"The stale nextval causes a real 23505",
"setval(max(id), true) moves the next value to 107 in this controlled case",
"The result records sequence identity and non-default increment"
],
"case_id": "sequence_lag_repair",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 9,
"preconditions": [
"A controlled, quiesced case schema",
"A sequence with START 100 and INCREMENT 7"
],
"repair": "Inspect the sequence and table, then repair only under a controlled writer-free window; handle an empty table and non-default bounds/increment separately.",
"trigger": "Insert an explicit key equal to the sequence's first value, then call nextval.",
"versions": [
"10",
"18"
]
}cases · index_build_conflict
{
"assertions": [
"Both failures are 23505 with the index-build message template",
"The regular build leaves no index",
"The concurrent failure's actual pg_index state is recorded and is not generalized to every CIC failure"
],
"case_id": "index_build_conflict",
"cleanup": "Drop any leftover indexes and the case schema with an owner connection.",
"has_snippet": false,
"position": 10,
"preconditions": [
"Duplicate table rows",
"Owner connection for index cleanup"
],
"repair": "Resolve duplicates, drop an invalid concurrent index when present, and retry the appropriate build.",
"trigger": "Build a regular unique index and then a concurrent unique index over duplicate rows.",
"versions": [
"10",
"18"
]
}cases · diagnostic_visibility
{
"assertions": [
"SQLSTATE and protocol object fields remain available",
"The key detail can be omitted when the role cannot inspect the key columns"
],
"case_id": "diagnostic_visibility",
"cleanup": "Drop the role, table, and schema with an owner connection.",
"has_snippet": false,
"position": 11,
"preconditions": [
"A restricted login role with INSERT but no SELECT privilege",
"A seeded unique row"
],
"repair": "Use permitted diagnostics and server logs; do not assume detail is always present.",
"trigger": "The restricted role inserts a duplicate key.",
"versions": [
"10",
"18"
]
}cases · log_fields
{
"assertions": [
"CSV/JSON log records expose SQLSTATE, message, and detail",
"The protocol constraint_name is not treated as a CSV/JSON standard key",
"The exact emitted record is tied to this run"
],
"case_id": "log_fields",
"cleanup": "Stop and remove only the runner-owned cluster or container.",
"has_snippet": false,
"position": 12,
"preconditions": [
"A dedicated cluster with logging_collector and csvlog; jsonlog when supported"
],
"repair": "Correlate logs with SQLSTATE and message fields; obtain object identity from the ErrorResponse or structured server context where available.",
"trigger": "Cause a duplicate-key error and read the collector output.",
"versions": [
"10",
"18"
]
}claims · identity.class-and-condition
{
"claim_id": "identity.class-and-condition",
"limits": "This establishes directory identity; it does not assert that every possible call site has been executed.",
"method": "Read the frozen errcodes.txt row and section.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "23505 is the unique_violation condition in Class 23 integrity_constraint_violation."
}claims · runtime.dml-template
{
"claim_id": "runtime.dml-template",
"limits": "The key detail is conditional on permission/RLS and available key values.",
"method": "Trace ereport and BuildIndexValueDescription in the fixed source snapshot; compare with dml_unique_conflict and diagnostic_visibility runs.",
"position": 1,
"runtime": [],
"sources": [
"src.nbtinsert.18.6",
"src.genam.18.6"
],
"statement": "The nbtree unique-check path emits SQLSTATE 23505 with duplicate key value violates unique constraint and, when visible, Key ... already exists."
}claims · runtime.protocol-fields
{
"claim_id": "runtime.protocol-fields",
"limits": "Log formats can gain fields in later releases; constraint_name is not inferred as a standard CSV/JSON key from a protocol field. The earlier full run is retained as a historical audit record but its first-record log_fields selection is excluded from this claim.",
"method": "Read the protocol field table and CSV/JSON logging field tables; inspect the records selected by the corrected log_fields run using backend PID, schema, table, constraint, message, and detail.",
"position": 2,
"runtime": [],
"sources": [
"doc.protocol.18",
"doc.logging.18"
],
"statement": "schema_name, table_name, and constraint_name are ErrorResponse object fields, while standard CSV/JSON logs expose SQLSTATE, message, and detail under their logging schemas."
}claims · runtime.index-build-template
{
"claim_id": "runtime.index-build-template",
"limits": "The invalid-state observation is limited to the duplicate scan failure in this run; other CIC failure stages require separate tests.",
"method": "Read the index-build ereport and concurrent-build phases; inspect pg_class/pg_index after both real failures.",
"position": 3,
"runtime": [],
"sources": [
"src.tuplesortvariants.18.6",
"doc.create-index.18.6"
],
"statement": "Unique index construction uses the separate could not create unique index template; a duplicate found in this CIC scan leaves an invalid index row, while this regular failed build leaves no row after rollback."
}claims · runtime.logical-apply-sqlstate
{
"claim_id": "runtime.logical-apply-sqlstate",
"limits": "No publisher/subscriber topology was run in this batch, so this is source/documentation evidence rather than a runtime observation.",
"method": "Read ReportApplyConflict and errcode_apply_conflict in the fixed source snapshot and compare the official conflict documentation.",
"position": 4,
"runtime": [],
"sources": [
"src.logical-conflict.18.6"
],
"statement": "PG18 logical apply classifies insert_exists, update_exists, and multiple_unique_conflicts and maps those conflict paths to SQLSTATE 23505."
}claims · runtime.tx-contexts
{
"claim_id": "runtime.tx-contexts",
"limits": "Connection status names are captured through psycopg 3; other clients may expose equivalent states differently.",
"method": "Read transaction and PL/pgSQL contracts and assert status transitions in explicit_tx_abort_recovery, savepoint_recovery, deferred_commit_conflict, and plpgsql_exception_recovery.",
"position": 5,
"runtime": [],
"sources": [
"doc.transactions.18",
"doc.plpgsql.18"
],
"statement": "A 23505 aborts an explicit transaction until rollback, can be isolated with ROLLBACK TO SAVEPOINT, can surface at COMMIT for a deferred unique constraint, and can be caught by a PL/pgSQL EXCEPTION subtransaction."
}claims · runtime.retry-boundary
{
"claim_id": "runtime.retry-boundary",
"limits": "The case demonstrates the conflict and lock ordering, not that a particular application transaction is safe to retry.",
"method": "Read the official serialization-failure handling guidance and run an explicit lock-synchronized concurrent unique conflict.",
"position": 6,
"runtime": [],
"sources": [
"doc.mvcc.18"
],
"statement": "PostgreSQL documents cases where 23505 from concurrent key selection can be retried, but the retry must include the complete transaction and may remain a persistent conflict."
}claims · runtime.on-conflict-scope
{
"claim_id": "runtime.on-conflict-scope",
"limits": "Whether DO NOTHING or DO UPDATE is correct remains a business policy; idempotency requires request and existing-result validation.",
"method": "Read conflict-target rules and execute the case with a pre-existing phone row.",
"position": 7,
"runtime": [],
"sources": [
"doc.insert.18.6"
],
"statement": "ON CONFLICT (email) only handles its inferred arbiter; a phone-only collision still raises 23505, while omitted-target DO NOTHING handles a usable unique conflict."
}claims · runtime.sequence-repair-limit
{
"claim_id": "runtime.sequence-repair-limit",
"limits": "Empty tables, sequence identity, bounds, cache, non-default ownership and concurrent writers need separate checks.",
"method": "Read setval semantics and execute START 100 INCREMENT 7 with a writer-free case schema.",
"position": 8,
"runtime": [],
"sources": [
"doc.sequence.18"
],
"statement": "setval(max(id), true) advances the next value in the controlled non-default increment case, but it is not a universal sequence repair."
}claims · runtime.nulls-choice
{
"claim_id": "runtime.nulls-choice",
"limits": "The case covers the DDL choice, not an upgrade of an existing catalog across every release.",
"method": "Execute an explicit NULLS NOT DISTINCT constraint on PG18 and mark the PG10 syntax as not applicable.",
"position": 9,
"runtime": [],
"sources": [
"doc.insert.18.6"
],
"statement": "UNIQUE NULLS NOT DISTINCT is an explicit PG15+ declaration; the default remains NULLS DISTINCT and is not changed merely by upgrading."
}claims · runtime.detail-visibility
{
"claim_id": "runtime.detail-visibility",
"limits": "Other privileges, RLS policies, expression indexes, and server configuration can change which fields are visible.",
"method": "Trace ACL/RLS checks and execute diagnostic_visibility with INSERT-only privilege.",
"position": 10,
"runtime": [],
"sources": [
"src.genam.18.6"
],
"statement": "A role without SELECT privilege on unique key columns can receive SQLSTATE and protocol object fields while the key DETAIL is omitted."
}claims · runtime.version-boundary
{
"claim_id": "runtime.version-boundary",
"limits": "This is a bounded PG14.24/PG15.19 comparison for the explicit NULLS NOT DISTINCT case. The PG14 syntax error is not 23505 coverage, and the result does not replace the selected base 18.6/10.21 case counts or establish every intermediate release.",
"method": "Compare the two fixed version-boundary summaries for the same registry case, including ordinary NULL behavior, explicit declaration result, transaction status, and repair count.",
"position": 11,
"runtime": [],
"sources": [
"doc.insert.18.6",
"runtime.23505-boundary-pg14-20260909.pg14",
"runtime.23505-boundary-pg15-20260909.pg15"
],
"statement": "On the fixed version-boundary registry case, PostgreSQL 14.24 accepts two ordinary NULLs but rejects UNIQUE NULLS NOT DISTINCT with syntax error 42601 and no 23505; PostgreSQL 15.19 accepts the declaration and raises 23505 on the second NULL, then remains IDLE for the valid repair."
}messages · message.dml.nbtree
{
"limits": "Template values and DETAIL depend on relation name and diagnostic visibility.",
"message_id": "message.dml.nbtree",
"path": "",
"position": 0,
"raw": {
"detail_template": "Key %s already exists.",
"id": "message.dml.nbtree",
"limits": "Template values and DETAIL depend on relation name and diagnostic visibility.",
"primary_template": "duplicate key value violates unique constraint \"%s\"",
"severity_source": "E",
"sources": [
"src.nbtinsert.18.6"
],
"sqlstate": "23505"
},
"severity": "E",
"sources": [
"src.nbtinsert.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "duplicate key value violates unique constraint \" \"",
"position": 0,
"role": "",
"template": "duplicate key value violates unique constraint \"%s\""
},
{
"kind": "detail",
"literal": "Key already exists.",
"position": 1,
"role": "",
"template": "Key %s already exists."
}
]
}messages · message.index-build
{
"limits": "This is the unique-index build path, not the ordinary DML template.",
"message_id": "message.index-build",
"path": "",
"position": 1,
"raw": {
"detail_template": "Key %s is duplicated.",
"id": "message.index-build",
"limits": "This is the unique-index build path, not the ordinary DML template.",
"primary_template": "could not create unique index \"%s\"",
"severity_source": "E",
"sources": [
"src.tuplesortvariants.18.6"
],
"sqlstate": "23505"
},
"severity": "E",
"sources": [
"src.tuplesortvariants.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "could not create unique index \" \"",
"position": 0,
"role": "",
"template": "could not create unique index \"%s\""
},
{
"kind": "detail",
"literal": "Key is duplicated.",
"position": 1,
"role": "",
"template": "Key %s is duplicated."
}
]
}messages · message.logical-apply
{
"limits": "The detail is dynamically assembled in err_detail.data and passed through errdetail_internal(\"%s\", err_detail.data); this is not a fixed user-facing template. The PG18 conflict label is source-confirmed; this batch did not run logical replication.",
"message_id": "message.logical-apply",
"path": "",
"position": 2,
"raw": {
"detail_template": "%s",
"id": "message.logical-apply",
"limits": "The detail is dynamically assembled in err_detail.data and passed through errdetail_internal(\"%s\", err_detail.data); this is not a fixed user-facing template. The PG18 conflict label is source-confirmed; this batch did not run logical replication.",
"primary_template": "conflict detected on relation \"%s.%s\": conflict=%s",
"sources": [
"src.logical-conflict.18.6"
],
"sqlstate": "23505"
},
"severity": "",
"sources": [
"src.logical-conflict.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "conflict detected on relation \" . \": conflict=",
"position": 0,
"role": "",
"template": "conflict detected on relation \"%s.%s\": conflict=%s"
},
{
"kind": "detail",
"literal": "",
"position": 1,
"role": "",
"template": "%s"
}
]
}runtimes · runtime.23505-final-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"deferred_commit_conflict",
"concurrent_unique_conflict",
"nulls_not_distinct",
"index_build_conflict",
"diagnostic_visibility"
],
"limits": "The selected cases are the full run scenarios not replaced by a more targeted final record; its former log_fields selection is excluded because the targeted run provides the exact event correlation.",
"position": 0,
"raw": {
"cases": [
"deferred_commit_conflict",
"concurrent_unique_conflict",
"nulls_not_distinct",
"index_build_conflict",
"diagnostic_visibility"
],
"id": "runtime.23505-final-20260909.latest",
"limits": "The selected cases are the full run scenarios not replaced by a more targeted final record; its former log_fields selection is excluded because the targeted run provides the exact event correlation.",
"raw": "verify/results/23505-final-20260909/latest/raw.jsonl",
"run_id": "23505-final-20260909",
"selection_status": "selected_for_unreplaced_cases",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"status": "passed",
"summary": "verify/results/23505-final-20260909/latest/summary.json",
"target": "latest"
},
"run_id": "23505-final-20260909",
"runtime_id": "runtime.23505-final-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"deferred_commit_conflict",
"concurrent_unique_conflict",
"index_build_conflict",
"diagnostic_visibility"
],
"limits": "The selected cases are the full run scenarios not replaced by a more targeted final record; its former log_fields selection is excluded because the targeted run provides the exact event correlation.",
"position": 1,
"raw": {
"cases": [
"deferred_commit_conflict",
"concurrent_unique_conflict",
"index_build_conflict",
"diagnostic_visibility"
],
"cases_not_applicable": [
"nulls_not_distinct"
],
"cases_passed": 11,
"id": "runtime.23505-final-20260909.pg10",
"image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
"limits": "The selected cases are the full run scenarios not replaced by a more targeted final record; its former log_fields selection is excluded because the targeted run provides the exact event correlation.",
"raw": "verify/results/23505-final-20260909/pg10/raw.jsonl",
"run_id": "23505-final-20260909",
"selection_status": "selected_for_unreplaced_cases",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"status": "passed",
"summary": "verify/results/23505-final-20260909/pg10/summary.json",
"target": "pg10"
},
"run_id": "23505-final-20260909",
"runtime_id": "runtime.23505-final-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-snippet-contract-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"plpgsql_exception_recovery",
"on_conflict_target_scope",
"sequence_lag_repair"
],
"limits": "The selected cases are the registry-backed PL/pgSQL, ON CONFLICT, and sequence excerpts; explicit transaction and savepoint cases use the manual-boundary runs below.",
"position": 2,
"raw": {
"cases": [
"plpgsql_exception_recovery",
"on_conflict_target_scope",
"sequence_lag_repair"
],
"id": "runtime.23505-snippet-contract-20260909.latest",
"limits": "The selected cases are the registry-backed PL/pgSQL, ON CONFLICT, and sequence excerpts; explicit transaction and savepoint cases use the manual-boundary runs below.",
"raw": "verify/results/23505-snippet-contract-20260909/latest/raw.jsonl",
"run_id": "23505-snippet-contract-20260909",
"selection_status": "selected_for_registry_snippets",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": "verify/cases/23505/snippets.json",
"status": "passed",
"summary": "verify/results/23505-snippet-contract-20260909/latest/summary.json",
"target": "latest"
},
"run_id": "23505-snippet-contract-20260909",
"runtime_id": "runtime.23505-snippet-contract-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-snippet-contract-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"plpgsql_exception_recovery",
"on_conflict_target_scope",
"sequence_lag_repair"
],
"limits": "The selected cases are the registry-backed PL/pgSQL, ON CONFLICT, and sequence excerpts; explicit transaction and savepoint cases use the manual-boundary runs below.",
"position": 3,
"raw": {
"cases": [
"plpgsql_exception_recovery",
"on_conflict_target_scope",
"sequence_lag_repair"
],
"id": "runtime.23505-snippet-contract-20260909.pg10",
"limits": "The selected cases are the registry-backed PL/pgSQL, ON CONFLICT, and sequence excerpts; explicit transaction and savepoint cases use the manual-boundary runs below.",
"raw": "verify/results/23505-snippet-contract-20260909/pg10/raw.jsonl",
"run_id": "23505-snippet-contract-20260909",
"selection_status": "selected_for_registry_snippets",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": "verify/cases/23505/snippets.json",
"status": "passed",
"summary": "verify/results/23505-snippet-contract-20260909/pg10/summary.json",
"target": "pg10"
},
"run_id": "23505-snippet-contract-20260909",
"runtime_id": "runtime.23505-snippet-contract-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-log-fields-final-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"log_fields"
],
"limits": "This targeted run is the sole selected log_fields record; its backend PID, schema, table, constraint, message, and detail match the trigger.",
"position": 4,
"raw": {
"cases": [
"log_fields"
],
"id": "runtime.23505-log-fields-final-20260909.latest",
"limits": "This targeted run is the sole selected log_fields record; its backend PID, schema, table, constraint, message, and detail match the trigger.",
"observed": {
"backend_pid": 60638,
"correlation": "Both collector records match this case backend PID, schema, table, constraint, SQLSTATE, primary message, and DETAIL.",
"csv_record": {
"detail": "Key (token)=(logged) already exists.",
"message": "duplicate key value violates unique constraint \"logged_items_token_key\"",
"process_id": "60638",
"query": "INSERT INTO \"c23505_log_fields\".\"logged_items\" VALUES (2, 'logged')",
"sql_state_code": "23505"
},
"json_record": {
"detail": "Key (token)=(logged) already exists.",
"message": "duplicate key value violates unique constraint \"logged_items_token_key\"",
"pid": 60638,
"state_code": "23505",
"statement": "INSERT INTO \"c23505_log_fields\".\"logged_items\" VALUES (2, 'logged')"
},
"trigger": {
"constraint_name": "logged_items_token_key",
"message_detail": "Key (token)=(logged) already exists.",
"message_primary": "duplicate key value violates unique constraint \"logged_items_token_key\"",
"schema_name": "c23505_log_fields",
"sqlstate": "23505",
"table_name": "logged_items"
}
},
"raw": "verify/results/23505-log-fields-final-20260909/latest/raw.jsonl",
"raw_sha256": "91945d2220cb85882275675810fb9b85382e99a6b25b2e81e6d06e7751b8553f",
"run_id": "23505-log-fields-final-20260909",
"selection_status": "selected_exact_log_correlation",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-log-fields-final-20260909/latest/summary.json",
"summary_sha256": "4f398c31188efa509cc59f010e4cbac23751a48deac973a027ecb66903c8c817",
"target": "latest"
},
"run_id": "23505-log-fields-final-20260909",
"runtime_id": "runtime.23505-log-fields-final-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-log-fields-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"log_fields"
],
"limits": "This targeted run is the sole selected log_fields record; its backend PID, schema, table, constraint, message, and detail match the trigger.",
"position": 5,
"raw": {
"cases": [
"log_fields"
],
"id": "runtime.23505-log-fields-final-20260909.pg10",
"image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
"limits": "This targeted run is the sole selected log_fields record; its backend PID, schema, table, constraint, message, and detail match the trigger.",
"observed": {
"backend_pid": 81,
"correlation": "The CSV collector record matches this case backend PID, schema, table, constraint, SQLSTATE, primary message, and DETAIL; PG10 has no JSON logging output in this target configuration.",
"csv_record": {
"detail": "Key (token)=(logged) already exists.",
"message": "duplicate key value violates unique constraint \"logged_items_token_key\"",
"process_id": "81",
"query": "INSERT INTO \"c23505_log_fields\".\"logged_items\" VALUES (2, 'logged')",
"sql_state_code": "23505"
},
"json_record": null,
"trigger": {
"constraint_name": "logged_items_token_key",
"message_detail": "Key (token)=(logged) already exists.",
"message_primary": "duplicate key value violates unique constraint \"logged_items_token_key\"",
"schema_name": "c23505_log_fields",
"sqlstate": "23505",
"table_name": "logged_items"
}
},
"raw": "verify/results/23505-log-fields-final-20260909/pg10/raw.jsonl",
"raw_sha256": "fc52475937c24be583212464ff74a70603118680f5d39b7e2938118473223711",
"run_id": "23505-log-fields-final-20260909",
"selection_status": "selected_exact_log_correlation",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-log-fields-final-20260909/pg10/summary.json",
"summary_sha256": "d24ef7ce7c8a40cba28b0b5952b404df6feee8038a9e531062885a852b3f77e9",
"target": "pg10"
},
"run_id": "23505-log-fields-final-20260909",
"runtime_id": "runtime.23505-log-fields-final-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-diagnostic-snippet-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"dml_unique_conflict"
],
"limits": "The selected DML diagnostic case is the targeted registry run; the broad base-run copy is retained only as local audit data.",
"position": 6,
"raw": {
"cases": [
"dml_unique_conflict"
],
"id": "runtime.23505-diagnostic-snippet-20260909.latest",
"limits": "The selected DML diagnostic case is the targeted registry run; the broad base-run copy is retained only as local audit data.",
"raw": "verify/results/23505-diagnostic-snippet-20260909/latest/raw.jsonl",
"run_id": "23505-diagnostic-snippet-20260909",
"selection_status": "selected_for_dml_diagnostic",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": "verify/cases/23505/snippets.json",
"status": "passed",
"summary": "verify/results/23505-diagnostic-snippet-20260909/latest/summary.json",
"target": "latest"
},
"run_id": "23505-diagnostic-snippet-20260909",
"runtime_id": "runtime.23505-diagnostic-snippet-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-diagnostic-snippet-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"dml_unique_conflict"
],
"limits": "The selected DML diagnostic case is the targeted registry run; the broad base-run copy is retained only as local audit data.",
"position": 7,
"raw": {
"cases": [
"dml_unique_conflict"
],
"id": "runtime.23505-diagnostic-snippet-20260909.pg10",
"limits": "The selected DML diagnostic case is the targeted registry run; the broad base-run copy is retained only as local audit data.",
"raw": "verify/results/23505-diagnostic-snippet-20260909/pg10/raw.jsonl",
"run_id": "23505-diagnostic-snippet-20260909",
"selection_status": "selected_for_dml_diagnostic",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": "verify/cases/23505/snippets.json",
"status": "passed",
"summary": "verify/results/23505-diagnostic-snippet-20260909/pg10/summary.json",
"target": "pg10"
},
"run_id": "23505-diagnostic-snippet-20260909",
"runtime_id": "runtime.23505-diagnostic-snippet-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-explicit-manual-final-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"explicit_tx_abort_recovery"
],
"limits": "This run proves that registry transaction statements execute with autocommit=True, so psycopg does not add an implicit BEGIN; it covers this explicit recovery case only.",
"position": 8,
"raw": {
"cases": [
"explicit_tx_abort_recovery"
],
"id": "runtime.23505-explicit-manual-final-20260909.latest",
"limits": "This run proves that registry transaction statements execute with autocommit=True, so psycopg does not add an implicit BEGIN; it covers this explicit recovery case only.",
"observed": {
"connection_autocommit": true,
"duplicate_sqlstate": "23505",
"repair_transaction": "BEGIN; INSERT; COMMIT",
"rows": [
[
1,
"seed"
],
[
2,
"after rollback"
]
],
"status_after_25p02": "INERROR",
"status_after_duplicate": "INERROR",
"status_after_rollback": "IDLE",
"transaction_control": [
"BEGIN",
"ROLLBACK",
"BEGIN",
"COMMIT"
]
},
"raw": "verify/results/23505-explicit-manual-final-20260909/latest/raw.jsonl",
"raw_sha256": "586bacd10d1e5d2a5a5ec58c2ed747d4b2b8618a051ce56b0d8307c7265e196d",
"run_id": "23505-explicit-manual-final-20260909",
"selection_status": "selected_manual_boundary",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-explicit-manual-final-20260909/latest/summary.json",
"summary_sha256": "38cd0161a97fa35084f192a5aa60f6061955b60ec681c4800b575514dee6a6f3",
"target": "latest"
},
"run_id": "23505-explicit-manual-final-20260909",
"runtime_id": "runtime.23505-explicit-manual-final-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-explicit-manual-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"explicit_tx_abort_recovery"
],
"limits": "This run proves that registry transaction statements execute with autocommit=True, so psycopg does not add an implicit BEGIN; it covers this explicit recovery case only.",
"position": 9,
"raw": {
"cases": [
"explicit_tx_abort_recovery"
],
"id": "runtime.23505-explicit-manual-final-20260909.pg10",
"image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
"limits": "This run proves that registry transaction statements execute with autocommit=True, so psycopg does not add an implicit BEGIN; it covers this explicit recovery case only.",
"observed": {
"connection_autocommit": true,
"duplicate_sqlstate": "23505",
"repair_transaction": "BEGIN; INSERT; COMMIT",
"rows": [
[
1,
"seed"
],
[
2,
"after rollback"
]
],
"status_after_25p02": "INERROR",
"status_after_duplicate": "INERROR",
"status_after_rollback": "IDLE",
"transaction_control": [
"BEGIN",
"ROLLBACK",
"BEGIN",
"COMMIT"
]
},
"raw": "verify/results/23505-explicit-manual-final-20260909/pg10/raw.jsonl",
"raw_sha256": "ed1c4f5082a00b67297a9d01b8362f7d70c758a2fbd393e20def6c450a6f5739",
"run_id": "23505-explicit-manual-final-20260909",
"selection_status": "selected_manual_boundary",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-explicit-manual-final-20260909/pg10/summary.json",
"summary_sha256": "4a4243d367afd9c142991aba496336c972e4fe3cc959a724d3454773986ac30b",
"target": "pg10"
},
"run_id": "23505-explicit-manual-final-20260909",
"runtime_id": "runtime.23505-explicit-manual-final-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-savepoint-manual-final-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"savepoint_recovery"
],
"limits": "This run proves the registry savepoint sequence executes with autocommit=True, so psycopg does not add an implicit BEGIN; it covers savepoint recovery only.",
"position": 10,
"raw": {
"cases": [
"savepoint_recovery"
],
"id": "runtime.23505-savepoint-manual-final-20260909.latest",
"limits": "This run proves the registry savepoint sequence executes with autocommit=True, so psycopg does not add an implicit BEGIN; it covers savepoint recovery only.",
"observed": {
"connection_autocommit": true,
"rows": [
[
1,
"seed"
],
[
2,
"outer"
],
[
3,
"after savepoint"
]
],
"statuses": {
"after_duplicate": "INERROR",
"after_rollback_to_savepoint": "INTRANS"
},
"transaction_control": [
"BEGIN",
"SAVEPOINT",
"ROLLBACK TO SAVEPOINT",
"RELEASE SAVEPOINT",
"COMMIT"
]
},
"raw": "verify/results/23505-savepoint-manual-final-20260909/latest/raw.jsonl",
"raw_sha256": "3b3e7305df8d70309f3c632e9b19b43cd9f1411f0967e952bff7997e5c0c7cb7",
"run_id": "23505-savepoint-manual-final-20260909",
"selection_status": "selected_manual_boundary",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-savepoint-manual-final-20260909/latest/summary.json",
"summary_sha256": "e9ff818a677f577321fb2faccb8d48bb62b054d9f579531a5231029cb16162ef",
"target": "latest"
},
"run_id": "23505-savepoint-manual-final-20260909",
"runtime_id": "runtime.23505-savepoint-manual-final-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.23505-savepoint-manual-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"savepoint_recovery"
],
"limits": "This run proves the registry savepoint sequence executes with autocommit=True, so psycopg does not add an implicit BEGIN; it covers savepoint recovery only.",
"position": 11,
"raw": {
"cases": [
"savepoint_recovery"
],
"id": "runtime.23505-savepoint-manual-final-20260909.pg10",
"image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
"limits": "This run proves the registry savepoint sequence executes with autocommit=True, so psycopg does not add an implicit BEGIN; it covers savepoint recovery only.",
"observed": {
"connection_autocommit": true,
"rows": [
[
1,
"seed"
],
[
2,
"outer"
],
[
3,
"after savepoint"
]
],
"statuses": {
"after_duplicate": "INERROR",
"after_rollback_to_savepoint": "INTRANS"
},
"transaction_control": [
"BEGIN",
"SAVEPOINT",
"ROLLBACK TO SAVEPOINT",
"RELEASE SAVEPOINT",
"COMMIT"
]
},
"raw": "verify/results/23505-savepoint-manual-final-20260909/pg10/raw.jsonl",
"raw_sha256": "74fb5d36973e351dead8e49c02f2e272979c0dae5d40fc6b631a9ea6f25c5742",
"run_id": "23505-savepoint-manual-final-20260909",
"selection_status": "selected_manual_boundary",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "74d7d700331bc3d9c190bf807cca31999ddf45e8cbea153ec7c6b6d4f9702686"
},
"status": "passed",
"summary": "verify/results/23505-savepoint-manual-final-20260909/pg10/summary.json",
"summary_sha256": "9f6dea66d73191045e35fe239ecff2c69fb046bdd90de5cc4351443f3bc0f4bf",
"target": "pg10"
},
"run_id": "23505-savepoint-manual-final-20260909",
"runtime_id": "runtime.23505-savepoint-manual-final-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}runtimes · runtime.23505-boundary-pg14-20260909.pg14 · 14.24 (Debian 14.24-1.pgdg13+2) · not_applicable
{
"cases": [
"nulls_not_distinct_version_boundary"
],
"limits": "The same registry case passed its assertions, but this target cannot execute the explicit feature. Its 42601 result is retained as a version-availability comparison and is not counted as an observed 23505 runtime.",
"position": 12,
"raw": {
"case_manifest": {
"path": "verify/cases/23505/cases.json",
"sha256": "e4d9376fa038675dcfd83c3fb3590b2bc43bb897dd5521be11474a7df0334776"
},
"case_status": "passed",
"cases": [
"nulls_not_distinct_version_boundary"
],
"id": "runtime.23505-boundary-pg14-20260909.pg14",
"limits": "The same registry case passed its assertions, but this target cannot execute the explicit feature. Its 42601 result is retained as a version-availability comparison and is not counted as an observed 23505 runtime.",
"observed": {
"explicit_feature": "unsupported_syntax",
"natural_23505_observed": false,
"ordinary_unique_null_count": 2,
"status_after_syntax": "IDLE",
"unsupported_primary": "syntax error at or near \"NULLS\"",
"unsupported_severity": "ERROR",
"unsupported_sqlstate": "42601"
},
"raw": "verify/results/23505-boundary-pg14-20260909/pg14/raw.jsonl",
"raw_sha256": "d21fcb5f18c65a8e941814b8c4046b84700c59ce14b73ced51d2f8ac574552fc",
"run_id": "23505-boundary-pg14-20260909",
"selection_status": "selected_boundary_comparison",
"server_version": "14.24 (Debian 14.24-1.pgdg13+2)",
"server_version_num": 140024,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "2535a5a74138b3e7896f1d06e1109be42f62a49b4dac25e3f842d60c30b21a95"
},
"status": "not_applicable",
"summary": "verify/results/23505-boundary-pg14-20260909/pg14/summary.json",
"summary_sha256": "e757ffaea0ee44d8f5ee5f4187798809d0c63a40020ff575a763e4cabb960f75",
"target": "pg14",
"target_status": "passed"
},
"run_id": "23505-boundary-pg14-20260909",
"runtime_id": "runtime.23505-boundary-pg14-20260909.pg14",
"server_version": "14.24 (Debian 14.24-1.pgdg13+2)",
"status": "not_applicable",
"target": "pg14"
}runtimes · runtime.23505-boundary-pg15-20260909.pg15 · 15.19 (Debian 15.19-1.pgdg13+2) · passed
{
"cases": [
"nulls_not_distinct_version_boundary"
],
"limits": "This is a separate PG15 boundary comparison for the explicit NULLS NOT DISTINCT case; it does not replace or inflate the selected base runtime cases.",
"position": 13,
"raw": {
"case_manifest": {
"path": "verify/cases/23505/cases.json",
"sha256": "e4d9376fa038675dcfd83c3fb3590b2bc43bb897dd5521be11474a7df0334776"
},
"case_status": "passed",
"cases": [
"nulls_not_distinct_version_boundary"
],
"id": "runtime.23505-boundary-pg15-20260909.pg15",
"limits": "This is a separate PG15 boundary comparison for the explicit NULLS NOT DISTINCT case; it does not replace or inflate the selected base runtime cases.",
"observed": {
"explicit_constraint": "nulls_not_distinct_uq",
"explicit_detail": "Key (external_id)=(null) already exists.",
"explicit_feature": "supported",
"explicit_primary": "duplicate key value violates unique constraint \"nulls_not_distinct_uq\"",
"explicit_severity": "ERROR",
"explicit_sqlstate": "23505",
"natural_23505_observed": true,
"ordinary_unique_null_count": 2,
"repaired_row_count": 2,
"status_after_duplicate": "IDLE"
},
"raw": "verify/results/23505-boundary-pg15-20260909/pg15/raw.jsonl",
"raw_sha256": "d2bd7a499b4c9355f209e0831b3dbba8bcc98c8149010dcc9f13135ae05ed97a",
"run_id": "23505-boundary-pg15-20260909",
"selection_status": "selected_boundary_comparison",
"server_version": "15.19 (Debian 15.19-1.pgdg13+2)",
"server_version_num": 150019,
"snippet_registry": {
"path": "verify/cases/23505/snippets.json",
"sha256": "2535a5a74138b3e7896f1d06e1109be42f62a49b4dac25e3f842d60c30b21a95"
},
"status": "passed",
"summary": "verify/results/23505-boundary-pg15-20260909/pg15/summary.json",
"summary_sha256": "df4d1f90eaca2155359bc7b141734a1026d7e1893400e5e6352ac1e95461137d",
"target": "pg15",
"target_status": "passed"
},
"run_id": "23505-boundary-pg15-20260909",
"runtime_id": "runtime.23505-boundary-pg15-20260909.pg15",
"server_version": "15.19 (Debian 15.19-1.pgdg13+2)",
"status": "passed",
"target": "pg15"
}sources · src.errcodes.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 235-241",
"path": "src/backend/utils/errcodes.txt",
"position": 0,
"sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
"source_id": "src.errcodes.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}sources · src.nbtinsert.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 640-674",
"path": "src/backend/access/nbtree/nbtinsert.c",
"position": 1,
"sha256": "199671bec6b07b80100ea41632cef4b03a9525df75a2ede2b8fe155b637dcba7",
"source_id": "src.nbtinsert.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/access/nbtree/nbtinsert.c#L640-L674"
}sources · src.genam.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 155-275",
"path": "src/backend/access/index/genam.c",
"position": 2,
"sha256": "11897b1d8b1ae1f4a1bef9a72e740da7aa83579abf84e4ca5ebacd6530874c28",
"source_id": "src.genam.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/access/index/genam.c#L155-L275"
}sources · src.tuplesortvariants.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 1670-1694",
"path": "src/backend/utils/sort/tuplesortvariants.c",
"position": 3,
"sha256": "f160e11ec100be7e05db8abba7587e8fd0e092110d56f917d2d4dac0a58261ca",
"source_id": "src.tuplesortvariants.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/sort/tuplesortvariants.c#L1670-L1694"
}sources · src.logical-conflict.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 102-131, 168-180",
"path": "src/backend/replication/logical/conflict.c",
"position": 4,
"sha256": "1dc6959872c84bc0d0b402ab48c4050dd961185574971633bd698eadc1a56347",
"source_id": "src.logical-conflict.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/replication/logical/conflict.c#L102-L180"
}sources · doc.insert.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 363-430, 564-577",
"path": "doc/src/sgml/ref/insert.sgml",
"position": 5,
"sha256": "f93403779fb1d980cd5995a1e2741bbdae8404584407610f9aba33ec4724a39f",
"source_id": "doc.insert.18.6",
"tag": "REL_18_6",
"url": "https://www.postgresql.org/docs/18/sql-insert.html"
}sources · doc.create-index.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 620-683",
"path": "doc/src/sgml/ref/create_index.sgml",
"position": 6,
"sha256": "3698f11c6f447d127e4624a1a845dee4d5146b8337ddc6d895a7962e676717f8",
"source_id": "doc.create-index.18.6",
"tag": "REL_18_6",
"url": "https://www.postgresql.org/docs/18/sql-createindex.html"
}sources · doc.protocol.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "ErrorResponse field reference",
"path": "doc/src/sgml/protocol.sgml",
"position": 7,
"sha256": "2531c535a61c7d3bb15ea328aa249317a3d2cf069f5d0d945dce428af845ddfc",
"source_id": "doc.protocol.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/protocol-error-fields.html"
}sources · doc.logging.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "CSV and JSON logging fields",
"path": "doc/src/sgml/config.sgml",
"position": 8,
"sha256": "19c5d1126df83008f073ef52fcb45caf8ec511c6ac1ae231def833ea1711d0c9",
"source_id": "doc.logging.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/runtime-config-logging.html"
}sources · doc.mvcc.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "serialization and deadlock failure handling",
"path": "doc/src/sgml/mvcc.sgml",
"position": 9,
"sha256": "4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340",
"source_id": "doc.mvcc.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/mvcc-serialization-failure-handling.html"
}sources · doc.plpgsql.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "EXCEPTION blocks and upsert example",
"path": "doc/src/sgml/plpgsql.sgml",
"position": 10,
"sha256": "43d705adbded343336341fd3e34ea8940432e8a8211f737d36ba3041ad0a4a51",
"source_id": "doc.plpgsql.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/plpgsql-control-structures.html"
}sources · doc.sequence.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "setval(regclass,bigint[,boolean])",
"path": "doc/src/sgml/func.sgml",
"position": 11,
"sha256": "05d03f505dc3c3b4fb2b3a6e8ed3275c425306a8ff20dd9548e838c26bbb968a",
"source_id": "doc.sequence.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/functions-sequence.html"
}sources · doc.transactions.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "savepoint and transaction recovery",
"path": "doc/src/sgml/xact.sgml",
"position": 12,
"sha256": "b48fbe8bd02ce3d1181a350c88c8baa6e11c73edc90a936e77b180daef328c5c",
"source_id": "doc.transactions.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/tutorial-transactions.html"
}来源引用
定义来源
center · PostgreSQL 18 · english-manuals:80d4516037e6dac2ecaca604550622754952d6d2209097d343ab740fddb6091e
正文语言: zh-Hans · english-manuals:80d4516037e6dac2ecaca604550622754952d6d2209097d343ab740fddb6091e