From 5fe70d4b3ca6d731bb9611500bb6975f9b8aa370 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Tue, 1 Sep 2026 03:20:50 +0000 Subject: [PATCH v3] Restrict REPACK (CONCURRENTLY) on user catalog tables. Commit 28d534e2ae0 added the CONCURRENTLY option to REPACK. Unlike the default path, which rewrites the table through rewriteheap.c, the concurrent path is not MVCC-safe: it changes the visibility information of the tuples it rewrites. A table declared with the user_catalog_table storage parameter is read by an output plugin during logical decoding, using historical snapshots. Changing that visibility information can make the table's contents invisible to the plugin at some point, silently breaking decoding. check_concurrent_repack_requirements() already rejects system catalogs but did not consider tables used as catalog tables. Reject those too, the same way a table rewrite via ALTER TABLE already does, and document the limitation. Once REPACK (CONCURRENTLY) is made MVCC-safe, this check should stay unless the rewrite mappings are also written for user catalog tables. Backpatch to v19, where REPACK (CONCURRENTLY) was introduced. Reported-by: Nathan Bossart Author: Bharath Rupireddy Reviewed-by: Antonin Houska Discussion: https://postgr.es/m/apBIFWzHYOaG0auN%40nathan Backpatch-through: 19 --- contrib/test_decoding/expected/repack.out | 6 ++++++ contrib/test_decoding/sql/repack.sql | 5 +++++ doc/src/sgml/ref/repack.sgml | 8 ++++++++ src/backend/commands/repack.c | 15 +++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/contrib/test_decoding/expected/repack.out b/contrib/test_decoding/expected/repack.out index 5ddc63238c5..6ed0af0f8ad 100644 --- a/contrib/test_decoding/expected/repack.out +++ b/contrib/test_decoding/expected/repack.out @@ -61,6 +61,12 @@ HINT: Consider running the command on individual partitions. REPACK (CONCURRENTLY) pg_class; ERROR: cannot execute REPACK (CONCURRENTLY) on relation "pg_class" HINT: REPACK (CONCURRENTLY) is not supported for catalog relations. +-- Doesn't support tables used as catalog tables +CREATE TABLE repack_conc_user_catalog (i int) WITH (user_catalog_table = true); +REPACK (CONCURRENTLY) repack_conc_user_catalog; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_user_catalog" +HINT: REPACK (CONCURRENTLY) is not supported for tables used as catalog tables. +DROP TABLE repack_conc_user_catalog; -- Doesn't support TOAST tables directly CREATE TABLE repack_conc_toast (t text); SELECT reltoastrelid::regclass AS toast_rel diff --git a/contrib/test_decoding/sql/repack.sql b/contrib/test_decoding/sql/repack.sql index f461f5479f4..eb891009baf 100644 --- a/contrib/test_decoding/sql/repack.sql +++ b/contrib/test_decoding/sql/repack.sql @@ -42,6 +42,11 @@ REPACK (CONCURRENTLY) clstrpart; -- Disallowed in catalogs REPACK (CONCURRENTLY) pg_class; +-- Doesn't support tables used as catalog tables +CREATE TABLE repack_conc_user_catalog (i int) WITH (user_catalog_table = true); +REPACK (CONCURRENTLY) repack_conc_user_catalog; +DROP TABLE repack_conc_user_catalog; + -- Doesn't support TOAST tables directly CREATE TABLE repack_conc_toast (t text); SELECT reltoastrelid::regclass AS toast_rel 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..3da61437580 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -886,6 +886,21 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p) errhint("%s is not supported for catalog relations.", "REPACK (CONCURRENTLY)")); + /* + * Concurrent repack is not MVCC-safe, i.e. it changes visibility + * information, which can make the contents invisible to the output + * plugin. Once it is made MVCC-safe, the logical rewrite mappings must + * also be written for user catalog tables before this check can be + * removed. + */ + 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