REPACK (CONCURRENTLY) rewrites tables marked with user_catalog_table
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253571psql -h localhost -U postgresBuilt from patchset v4 (message #4), August 29, 2026 at 03:48 PM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t253571_4 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t253571_4 && git checkout t253571_4Patchset v4 (message #4) is on t253571_4
IIUC this can cause problems for logical replication consumers, since the
CONCURRENTLY path doesn't go through the rewriteheap.c machinery like the
non-concurrent path does:
CREATE TABLE t (a INT PRIMARY KEY, b TEXT) WITH (user_catalog_table = true);
ALTER TABLE t ALTER COLUMN b TYPE varchar(100); -- correctly fails
REPACK (CONCURRENTLY) t; -- should fail but doesn't
I believe the fix for v19 is to add a check for
RelationIsUsedAsCatalogTable() in check_concurrent_repack_requirements()
(plus a corresponding update to the list of CONCURRENTLY limitations in the
docs).
--
nathan
Hi,
On Thu, Aug 27, 2026 at 7:22 AM Nathan Bossart <nathandbossart@gmail.com> wrote:
IIUC this can cause problems for logical replication consumers, since the
CONCURRENTLY path doesn't go through the rewriteheap.c machinery like the
non-concurrent path does:CREATE TABLE t (a INT PRIMARY KEY, b TEXT) WITH (user_catalog_table = true);
ALTER TABLE t ALTER COLUMN b TYPE varchar(100); -- correctly fails
REPACK (CONCURRENTLY) t; -- should fail but doesn'tI believe the fix for v19 is to add a check for
RelationIsUsedAsCatalogTable() in check_concurrent_repack_requirements()
(plus a corresponding update to the list of CONCURRENTLY limitations in the
docs).
That's correct. I verified that concurrent repack doesn't write the
pg_logical/mappings files, which decoding later needs to correctly map
the old tuple locations to the new ones after a rewrite, unlike
non-concurrent CLUSTER, VACUUM FULL and REPACK on a user catalog
table. I think restricting user catalog tables, rather than making
concurrent repack support them, is the right choice at this point in
the release cycle.
Please find attached a patch with the suggested doc change. I didn't
add a test, I don't think we need one.
--
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com
Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:
Hi,
On Thu, Aug 27, 2026 at 7:22 AM Nathan Bossart <nathandbossart@gmail.com> wrote:
IIUC this can cause problems for logical replication consumers, since the
CONCURRENTLY path doesn't go through the rewriteheap.c machinery like the
non-concurrent path does:CREATE TABLE t (a INT PRIMARY KEY, b TEXT) WITH (user_catalog_table = true);
ALTER TABLE t ALTER COLUMN b TYPE varchar(100); -- correctly fails
REPACK (CONCURRENTLY) t; -- should fail but doesn'tI believe the fix for v19 is to add a check for
RelationIsUsedAsCatalogTable() in check_concurrent_repack_requirements()
(plus a corresponding update to the list of CONCURRENTLY limitations in the
docs).That's correct. I verified that concurrent repack doesn't write the
pg_logical/mappings files, which decoding later needs to correctly map
the old tuple locations to the new ones after a rewrite, unlike
non-concurrent CLUSTER, VACUUM FULL and REPACK on a user catalog
table. I think restricting user catalog tables, rather than making
concurrent repack support them, is the right choice at this point in
the release cycle.Please find attached a patch with the suggested doc change. I didn't
add a test, I don't think we need one.
Thanks! I'm just thinking about this comment:
+ /* The CONCURRENTLY path does not write logical rewrite mappings. */
IMO it makes no sense to rewrite the logical mappings as long as REPACK
(CONCURRENTLY) changes visibility information (i.e. it's MVCC-unsafe). Once we
implement the MVCC-safety, we should not remove this check unless we implement
the rewriting of the mappings for user catalog tables - that might also be
worth mentioning in the comment.
So far, I'd consider the MVCC-unsafety the primary reason to prohibit REPACK
(CONCURRENTLY) (or anyother MVCC-unsafe command) on the user catalog tables,
because it can make the contents of those tables invisible to the output
plugin at some point.
--
Antonin Houska
Web: https://www.cybertec-postgresql.com
Hi,
On Sat, Aug 29, 2026 at 4:23 AM Antonin Houska <ah@cybertec.at> wrote:
Thanks! I'm just thinking about this comment:
+ /* The CONCURRENTLY path does not write logical rewrite mappings. */
IMO it makes no sense to rewrite the logical mappings as long as REPACK
(CONCURRENTLY) changes visibility information (i.e. it's MVCC-unsafe). Once we
implement the MVCC-safety, we should not remove this check unless we implement
the rewriting of the mappings for user catalog tables - that might also be
worth mentioning in the comment.So far, I'd consider the MVCC-unsafety the primary reason to prohibit REPACK
(CONCURRENTLY) (or anyother MVCC-unsafe command) on the user catalog tables,
because it can make the contents of those tables invisible to the output
plugin at some point.
Thanks for pointing this out. I read the docs related to MVCC-safety
of concurrent repack. I reworded the comment as you suggested. Feel
free to suggest changes to it if any. Please find the attached v2
patch.
--
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com