From 39985bf011f4c82f4a523bccc3a100e6cba5cd82 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Thu, 27 Aug 2026 20:16:09 +0000 Subject: [PATCH v2] Restrict concurrent repack to the heap access method. Concurrent repack (28d534e2ae0) replays the data changes made during the table rewrite by decoding them from WAL, which only works if the table's access method supports logical decoding. check_concurrent_repack_requirements() didn't check for that. For an access method that doesn't support it, the concurrent changes are never decoded and are silently lost from the rewritten table. Fix by erroring out for tables that use a non-heap access method, and document the limitation. Recognizing logical-decoding support properly would need a new table AM callback, which is more than this open item warrants, so restrict it to heap for now. Backpatch to v19, where concurrent repack was introduced. Reported-by: Nathan Bossart Author: Bharath Rupireddy Reviewed-by: Nathan Bossart Reviewed-by: Masahiko Sawada Discussion: https://postgr.es/m/apBkixO4xAGFoiT3%40nathan Backpatch-through: 19 --- doc/src/sgml/ref/repack.sgml | 6 ++++++ src/backend/commands/repack.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/doc/src/sgml/ref/repack.sgml b/doc/src/sgml/ref/repack.sgml index 0cb72b6b289..0496cd24af1 100644 --- a/doc/src/sgml/ref/repack.sgml +++ b/doc/src/sgml/ref/repack.sgml @@ -285,6 +285,12 @@ REPACK [ ( option [, ...] ) ] USING + + + The table uses an access method other than heap. + + + REPACK is executed inside a transaction block. diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index 477c86b2ba6..05c0662a510 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -877,6 +877,20 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p) errdetail("%s requires \"wal_level\" to be set to \"replica\" or higher.", "REPACK (CONCURRENTLY)")); + /* + * A table AM that doesn't support logical decoding would cause concurrent + * repack to silently lose the changes made during the rewrite. Detecting + * such support cleanly would need a new table AM callback, so for now + * just restrict the command to heap. + */ + if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot execute %s on relation \"%s\"", + "REPACK (CONCURRENTLY)", RelationGetRelationName(rel)), + errhint("%s is only supported for the \"heap\" access method.", + "REPACK (CONCURRENTLY)")); + /* Data changes in system relations are not logically decoded. */ if (IsCatalogRelation(rel)) ereport(ERROR, -- 2.47.3