v1-0001-Reject-deferrable-primary-key-fallback-in-REPACK-.patch
application/octet-stream
Filename: v1-0001-Reject-deferrable-primary-key-fallback-in-REPACK-.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0001
Subject: Reject deferrable primary key fallback in REPACK CONCURRENTLY
| File | + | − |
|---|---|---|
| src/backend/commands/repack.c | 14 | 0 |
From d67bb43755896909663daa62fb0ae19b32b9d75e Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Fri, 17 Apr 2026 11:12:36 +0800
Subject: [PATCH v1] Reject deferrable primary key fallback in REPACK
CONCURRENTLY
REPACK CONCURRENTLY uses logical decoding to collect concurrent
changes and then replays them on the new heap. To locate rows for
UPDATE and DELETE replay, it requires an identity index.
When RelationGetReplicaIndex() returned InvalidOid, the code fell
back to rel->rd_pkindex if a primary key existed. That is not safe for
deferrable primary keys. Such indexes are not considered replica
identity indexes by WAL generation, so logical decoding may not provide
the old tuple needed by the repack output plugin.
This can make replay fail later with errors such as "incomplete delete
info" from the decoding worker.
Prevent the fallback when the primary key is deferrable, and report the
problem during the initial REPACK CONCURRENTLY checks instead.
Author: Chao Li <lic@highgo.com>
Reviewed-by:
Discussion: https://postgr.es/m/
---
src/backend/commands/repack.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 67364cc60e3..2c89cd17db4 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -926,7 +926,21 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p)
*/
ident_idx = RelationGetReplicaIndex(rel);
if (!OidIsValid(ident_idx) && OidIsValid(rel->rd_pkindex))
+ {
+ /*
+ * A deferrable primary key is not considered a replica identity
+ * index, so WAL may not contain the old tuple needed for replay.
+ */
+ if (rel->rd_ispkdeferrable)
+ ereport(ERROR,
+ errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("cannot process relation \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("Relation \"%s\" has a deferrable primary key.",
+ RelationGetRelationName(rel)));
+
ident_idx = rel->rd_pkindex;
+ }
if (!OidIsValid(ident_idx))
ereport(ERROR,
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
--
2.50.1 (Apple Git-155)