REPACK (CONCURRENTLY) rewrites tables marked with user_catalog_table

Started by Nathan Bossart3 days ago4 messageshackers
Beta feature

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.

appliessuccessCI history

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:t253571
psql -h localhost -U postgres

Built 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.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253571_4 && git checkout t253571_4

Patchset v4 (message #4) is on t253571_4

Jump to latest
#1Nathan Bossart
nathandbossart@gmail.com

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

#2Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Nathan Bossart (#1)
Re: REPACK (CONCURRENTLY) rewrites tables marked with user_catalog_table

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'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).

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

Attachments:

t253571_2
v1-0001-Restrict-concurrent-repack-on-user-catalog-tables.patchapplication/octet-stream; name=v1-0001-Restrict-concurrent-repack-on-user-catalog-tables.patchDownload+17-1
#3Antonin Houska
ah@cybertec.at
In reply to: Bharath Rupireddy (#2)
Re: REPACK (CONCURRENTLY) rewrites tables marked with user_catalog_table

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'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).

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

#4Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Antonin Houska (#3)
Re: REPACK (CONCURRENTLY) rewrites tables marked with user_catalog_table

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

Attachments:

t253571_4
v2-0001-Restrict-REPACK-CONCURRENTLY-on-user-catalog-tabl.patchapplication/octet-stream; name=v2-0001-Restrict-REPACK-CONCURRENTLY-on-user-catalog-tabl.patchDownload+23-1