Re: Global temporary tables

Zsolt Parragi <zsolt.parragi@percona.com>

From: Zsolt Parragi <zsolt.parragi@percona.com>
To: pgsql-hackers@lists.postgresql.org
Date: 2026-07-06T21:53:51Z
Lists: pgsql-hackers
Hello!

This is a great feature, I did some testing of it.

1. If a table has an ON COMMIT clause:

CREATE GLOBAL TEMPORARY TABLE gtt_del (id int) ON COMMIT DELETE ROWS

Then pg_dump forgets that.

2. Even an aborted transaction pins frozenxid:

CREATE GLOBAL TEMPORARY TABLE gtt (id int);

In one session

BEGIN; SELECT count(*) FROM gtt; ABORT;
-- and keep session alive

Then in another session,
SELECT datfrozenxid FROM pg_database WHERE datname=current_database();
-- do some work
VACUUM (FREEZE);
SELECT datfrozenxid FROM pg_database WHERE datname=current_database();
-- ...

And repeat the above a few times for the second session, datfrozenxid
will remain the same until the first session is closed.

3. in AtEOSubXact_UsageCleanup and also in AtEOSubXact_StorageCleanup

+		else
+			gtr_remove_usage(entry->relid);
+	}
+
+	/* Update the usage stopped subid */
+	if (entry->stopped_subid == mySubid)
+	{
+		if (isCommit)
+			entry->stopped_subid = parentSubid;
+		else
+			entry->stopped_subid = InvalidSubTransactionId;
+	}

if we follow the else branch with gtr_remove_usage, shouldn't the
function immediately return?

4. in AtEOSubXact_PendingInsertCleanup

+		else
+			hash_search(pending_inserts, &entry->relid, HASH_REMOVE, NULL);
+	}
+
+	/* Update the inserted subid (may rollback flush) */
+	if (entry->inserted_subid == mySubid)
+	{
+		if (isCommit)
+			entry->inserted_subid = parentSubid;
+		else
+		{
+			entry->inserted_subid = InvalidSubTransactionId;
+			have_inserts_to_flush = true;
+		}
+	}

same question, isn't the else branch missing a return?


5. in gtr_remove_usage / gtr_remove_all_usage_on_exit

+	shared_entry = dshash_find(gtr_shared_usage, &key, true);
+
+	if (shared_entry->usage_count > 1)

and in gtr_record_usage

+	/* Flag the usage entry for eoxact cleanup */
+	EOXactUsageListAdd(relid);
+
+	/* Add/update shared usage entry */
+	key.dbid = MyDatabaseId;
+	key.relid = relid;
+	shared_entry = dshash_find_or_insert(gtr_shared_usage, &key, &found);

Can't this crash with a null pointer access in the above if
dshash_find_or_insert fails with OOM?



Commits

  1. doc: clarify MERGE PARTITIONS adjacency requirement