From 4423be275ac65a7b0fc062ff319789d0205b2727 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Thu, 27 Aug 2026 22:41:00 +0000 Subject: [PATCH v1] Restrict concurrent repack on user catalog tables. Concurrent repack (28d534e2ae0) rewrites the table without going through the rewriteheap.c machinery that the non-concurrent path uses. That machinery logs old-to-new tuple location mappings under pg_logical/mappings, which logical decoding uses to resolve the cmin/cmax of catalog tuples relocated by the rewrite. check_concurrent_repack_requirements() didn't check whether the table is used as a catalog table. A table declared with user_catalog_table can be read by an output plugin during logical decoding. Without those mappings, such a consumer can no longer resolve the relocated tuples and is silently broken. Fix by erroring out for tables used as catalog tables, the same way a heap rewrite via ALTER TABLE already does, and document the limitation. Backpatch to v19, where concurrent repack was introduced. Reported-by: Nathan Bossart Author: Bharath Rupireddy Discussion: https://postgr.es/m/apBIFWzHYOaG0auN%40nathan Backpatch-through: 19 --- doc/src/sgml/ref/repack.sgml | 8 ++++++++ src/backend/commands/repack.c | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/doc/src/sgml/ref/repack.sgml b/doc/src/sgml/ref/repack.sgml index 0cb72b6b289..e2d5a34ba8b 100644 --- a/doc/src/sgml/ref/repack.sgml +++ b/doc/src/sgml/ref/repack.sgml @@ -285,6 +285,14 @@ REPACK [ ( option [, ...] ) ] USING + + + The table is declared as a catalog table using the + user_catalog_table + storage parameter. + + + REPACK is executed inside a transaction block. diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index 477c86b2ba6..39751af24af 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -886,6 +886,15 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p) errhint("%s is not supported for catalog relations.", "REPACK (CONCURRENTLY)")); + /* The CONCURRENTLY path does not write logical rewrite mappings. */ + if (RelationIsUsedAsCatalogTable(rel)) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot execute %s on relation \"%s\"", + "REPACK (CONCURRENTLY)", RelationGetRelationName(rel)), + errhint("%s is not supported for tables used as catalog tables.", + "REPACK (CONCURRENTLY)")); + /* * reorderbuffer.c does not seem to handle processing of TOAST relation * alone. -- 2.47.3