Ensure we have a snapshot when updating various system catalogs.
authorNathan Bossart <[email protected]>
Fri, 30 May 2025 20:17:28 +0000 (15:17 -0500)
committerNathan Bossart <[email protected]>
Fri, 30 May 2025 20:17:28 +0000 (15:17 -0500)
A few places that access system catalogs don't set up an active
snapshot before potentially accessing their TOAST tables.  To fix,
push an active snapshot just before each section of code that might
require accessing one of these TOAST tables, and pop it shortly
afterwards.  While at it, this commit adds some rather strict
assertions in an attempt to prevent such issues in the future.

Commit 16bf24e0e4 recently removed pg_replication_origin's TOAST
table in order to fix the same problem for that catalog.  On the
back-branches, those bugs are left in place.  We cannot easily
remove a catalog's TOAST table on released major versions, and only
replication origins with extremely long names are affected.  Given
the low severity of the issue, fixing older versions doesn't seem
worth the trouble of significantly modifying the patch.

Also, on v13 and v14, the aforementioned strict assertions have
been omitted because commit 2776922201, which added
HaveRegisteredOrActiveSnapshot(), was not back-patched.  While we
could probably back-patch it now, I've opted against it because it
seems unlikely that new TOAST snapshot issues will be introduced in
the oldest supported versions.

Reported-by: Alexander Lakhin <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Discussion: https://postgr.es/m/18127-fe54b6a667f29658%40postgresql.org
Discussion: https://postgr.es/m/18309-c0bf914950c46692%40postgresql.org
Discussion: https://postgr.es/m/ZvMSUPOqUU-VNADN%40nathan
Backpatch-through: 13

src/backend/commands/indexcmds.c
src/backend/commands/tablecmds.c
src/backend/postmaster/autovacuum.c

index c2904cdb1a77f99e07d8fa4afbac9e5b546d6e60..b658642ee9388c47409bc35a867ecb326a58e0f4 100644 (file)
@@ -4005,12 +4005,20 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
                                     get_rel_namespace(oldidx->tableId),
                                     false);
 
+       /*
+        * Swapping the indexes might involve TOAST table access, so ensure we
+        * have a valid snapshot.
+        */
+       PushActiveSnapshot(GetTransactionSnapshot());
+
        /*
         * Swap old index with the new one.  This also marks the new one as
         * valid and the old one as not valid.
         */
        index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
 
+       PopActiveSnapshot();
+
        /*
         * Invalidate the relcache for the table, so that after this commit
         * all sessions will refresh any cached plans that might reference the
index b411b87b91cad0aad0ebd982ea3dfcb35646ec42..ba3cc47801646a834aa97684d49931328652f781 100644 (file)
@@ -18220,9 +18220,17 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
        tab->rel = rel;
    }
 
+   /*
+    * Detaching the partition might involve TOAST table access, so ensure we
+    * have a valid snapshot.
+    */
+   PushActiveSnapshot(GetTransactionSnapshot());
+
    /* Do the final part of detaching */
    DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
 
+   PopActiveSnapshot();
+
    ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
 
    /* keep our lock until commit */
index e70f32d0ab4ca6549a433b094410aaccf7b5e648..b4e529efd8268f8ca0ea7b1a96843ce192ba28c0 100644 (file)
@@ -2321,6 +2321,12 @@ do_autovacuum(void)
                        get_namespace_name(classForm->relnamespace),
                        NameStr(classForm->relname))));
 
+       /*
+        * Deletion might involve TOAST table access, so ensure we have a
+        * valid snapshot.
+        */
+       PushActiveSnapshot(GetTransactionSnapshot());
+
        object.classId = RelationRelationId;
        object.objectId = relid;
        object.objectSubId = 0;
@@ -2333,6 +2339,7 @@ do_autovacuum(void)
         * To commit the deletion, end current transaction and start a new
         * one.  Note this also releases the locks we took.
         */
+       PopActiveSnapshot();
        CommitTransactionCommand();
        StartTransactionCommand();