From 5d5910d9abf0dbb469025399c7d42ac69d12fdf8 Mon Sep 17 00:00:00 2001
From: Dean Rasheed <dean.a.rasheed@gmail.com>
Date: Tue, 4 Aug 2026 19:28:01 +0100
Subject: [PATCH v10 11/11] Add DISCARD GLOBAL TEMP.

DISCARD GLOBAL TEMP deletes all storage created for global temporary
relations used in the current session, and removes all usage records.
This restores all global temporary relations back to their original
uninitialized state, as they were at the start of the session.
---
 doc/src/sgml/ref/discard.sgml             |  16 +-
 src/backend/catalog/global_temp.c         | 216 ++++++++++++++++++++++
 src/backend/commands/discard.c            |   8 +-
 src/backend/parser/gram.y                 |  16 +-
 src/backend/tcop/utility.c                |   3 +
 src/backend/utils/cache/gtcatcache.c      |  33 ++++
 src/bin/psql/tab-complete.in.c            |   2 +-
 src/include/catalog/global_temp.h         |   1 +
 src/include/nodes/parsenodes.h            |   1 +
 src/include/tcop/cmdtaglist.h             |   1 +
 src/include/utils/gtcatcache.h            |   1 +
 src/test/regress/expected/global_temp.out |  66 +++++++
 src/test/regress/sql/global_temp.sql      |  26 +++
 13 files changed, 386 insertions(+), 4 deletions(-)

diff --git a/doc/src/sgml/ref/discard.sgml b/doc/src/sgml/ref/discard.sgml
index bf44c523cac..0e37deb3530 100644
--- a/doc/src/sgml/ref/discard.sgml
+++ b/doc/src/sgml/ref/discard.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP }
+DISCARD { ALL | GLOBAL TEMPORARY | GLOBAL TEMP | PLANS | SEQUENCES | TEMPORARY | TEMP }
 </synopsis>
  </refsynopsisdiv>
 
@@ -42,6 +42,19 @@ DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP }
 
   <variablelist>
 
+   <varlistentry>
+    <term><literal>GLOBAL TEMPORARY</literal> or <literal>GLOBAL TEMP</literal></term>
+    <listitem>
+     <para>
+      Deletes all data from global temporary tables used in the current
+      session, and resets all global temporary sequences to their initial
+      state.  When the enclosing transaction is committed, all physical
+      storage created for global temporary relations used in the session
+      is deleted.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>PLANS</literal></term>
     <listitem>
@@ -90,6 +103,7 @@ RESET ALL;
 DEALLOCATE ALL;
 UNLISTEN *;
 SELECT pg_advisory_unlock_all();
+DISCARD GLOBAL TEMP;
 DISCARD PLANS;
 DISCARD TEMP;
 DISCARD SEQUENCES;
diff --git a/src/backend/catalog/global_temp.c b/src/backend/catalog/global_temp.c
index fe1a352fb2c..eb934e48363 100644
--- a/src/backend/catalog/global_temp.c
+++ b/src/backend/catalog/global_temp.c
@@ -55,6 +55,7 @@
 #include "access/genam.h"
 #include "access/multixact.h"
 #include "access/parallel.h"
+#include "access/relation.h"
 #include "access/table.h"
 #include "access/tableam.h"
 #include "access/xact.h"
@@ -182,6 +183,11 @@ static SubTransactionId processed_dropped_subid = InvalidSubTransactionId;
  */
 static bool update_tempfrozenxids = false;
 
+/*
+ * Subtransaction ID in which we executed DISCARD GLOBAL TEMP.
+ */
+static SubTransactionId discard_subid = InvalidSubTransactionId;
+
 /*
  * gtr_shared_usage
  *
@@ -654,6 +660,65 @@ gtr_remove_usage(Oid relid)
 	}
 }
 
+/*
+ * gtr_finalize_discard
+ *
+ *	Final stage of DISCARD GLOBAL TEMP/TEMPORARY.  This is invoked on commit,
+ *	if no additional user global temporary relations were created or reopened
+ *	after the DISCARD --- see DiscardGlobalTempRelations().
+ */
+static void
+gtr_finalize_discard(void)
+{
+	HASH_SEQ_STATUS status;
+	GtrUsageEntry *usage_entry;
+
+	/*
+	 * By the time we get here, all storage for user-defined global temporary
+	 * relations should have been deleted.  Delete all remaining storage (for
+	 * global temporary system catalog relations).
+	 */
+	if (gtr_local_storage)
+	{
+		ProcNumber	backend;
+		GtrStorageEntry *storage_entry;
+
+		backend = ProcNumberForTempRelations();
+
+		hash_seq_init(&status, gtr_local_storage);
+		while ((storage_entry = hash_seq_search(&status)) != NULL)
+		{
+			SMgrRelation srel;
+
+			Assert(IsCatalogRelationOid(storage_entry->relid));
+
+			srel = smgropen(storage_entry->rlocator, backend);
+			smgrdounlinkall(&srel, 1, false);
+			smgrclose(srel);
+
+			(void) hash_search(gtr_local_storage, &storage_entry->rlocator,
+							   HASH_REMOVE, NULL);
+
+			RelationMarkInvalid(storage_entry->relid);
+		}
+	}
+
+	/* Remove all usage records */
+	hash_seq_init(&status, gtr_local_usage);
+	while ((usage_entry = hash_seq_search(&status)) != NULL)
+	{
+		gtr_remove_usage(usage_entry->relid);
+		RelationMarkInvalid(usage_entry->relid);
+	}
+
+	/* Discard all cached pg_temp_class and pg_temp_index tuples */
+	GTCatCacheDiscard();
+
+	/* Reset tempfrozenxid and tempminmxid for this backend */
+	MyProc->tempfrozenxid = InvalidTransactionId;
+	MyProc->tempminmxid = InvalidMultiXactId;
+}
+
 /*
  * AtEOXact_UsageCleanup
  *
@@ -1396,6 +1461,38 @@ AtEOXact_GlobalTempRelation(bool isCommit)
 	processing_invalidated_gtrs = false;
 	processed_dropped_subid = InvalidSubTransactionId;
 
+	/*
+	 * Are we committing a DISCARD GLOBAL TEMP?
+	 *
+	 * DiscardGlobalTempRelations() scheduled all storage for user-defined
+	 * relations to be deleted, and by this point, all hash table entries for
+	 * that storage will have been removed.  However, we must check if there
+	 * is any new storage for any user-defined relations, in case any global
+	 * temporary relations were created or reopened after the DISCARD.
+	 */
+	if (discard_subid != InvalidSubTransactionId && isCommit)
+	{
+		bool		discard_ok = true;
+
+		if (gtr_local_storage)
+		{
+			hash_seq_init(&status, gtr_local_storage);
+			while ((storage_entry = hash_seq_search(&status)) != NULL)
+			{
+				if (!IsCatalogRelationOid(storage_entry->relid))
+				{
+					discard_ok = false;
+					hash_seq_term(&status);
+					break;
+				}
+			}
+		}
+
+		if (discard_ok)
+			gtr_finalize_discard();
+	}
+	discard_subid = InvalidSubTransactionId;
+
 	/* Clean up global temporary catalog caches */
 	AtEOXact_GTCatCache(isCommit);
 
@@ -1488,6 +1585,15 @@ AtEOSubXact_GlobalTempRelation(bool isCommit, SubTransactionId mySubid,
 			processed_dropped_subid = InvalidSubTransactionId;
 	}
 
+	/* Update discard_subid */
+	if (discard_subid == mySubid)
+	{
+		if (isCommit)
+			discard_subid = parentSubid;
+		else
+			discard_subid = InvalidSubTransactionId;
+	}
+
 	/* Clean up global temporary catalog caches */
 	AtEOSubXact_GTCatCache(isCommit, mySubid, parentSubid);
 
@@ -1573,3 +1679,113 @@ GetAllGlobalTempRelationsInUse(Oid dbid)
 
 	return rels_in_use;
 }
+
+/*
+ * DiscardGlobalTempRelations
+ *
+ *	DISCARD GLOBAL TEMP/TEMPORARY --- delete all storage created for global
+ *	temporary relations and remove all usage records, restoring the session to
+ *	the state it had before any global temporary relations were opened.
+ */
+void
+DiscardGlobalTempRelations(void)
+{
+	/*
+	 * This is a two stage process.  In the first stage (here), we remove all
+	 * storage associated with user-defined global temporary relations, but we
+	 * keep their usage records and global temporary system catalog entries.
+	 * In the second stage (on main transaction commit), if the DISCARD has
+	 * survived without (sub)transaction rollback, and all the user-defined
+	 * relations still have no storage (none were created or reopened), we
+	 * remove all remaining storage (the storage used by global temporary
+	 * system catalog relations) and delete all storage and usage records.
+	 */
+	if (gtr_local_usage != NULL)
+	{
+		List	   *relids = NIL;
+		HASH_SEQ_STATUS status;
+		GtrUsageEntry *entry;
+
+		hash_seq_init(&status, gtr_local_usage);
+		while ((entry = hash_seq_search(&status)) != NULL)
+		{
+			Oid			relid = entry->relid;
+			Relation	rel;
+			RelFileNumber newrelfilenumber;
+			HeapTuple	tuple;
+			Form_pg_temp_class form;
+
+			/* Skip system catalogs */
+			if (IsCatalogRelationOid(relid))
+				continue;
+
+			/* Skip dropped relations */
+			if (entry->stopped_subid != InvalidSubTransactionId)
+				continue;
+
+			/* Skip relations that don't have storage */
+			if (!RELKIND_HAS_STORAGE(entry->relkind))
+				continue;
+
+			/*
+			 * Schedule the relation's current storage for deletion and
+			 * allocate a new relfilenumber, but don't actually create new
+			 * storage.  The new storage will be created if it is reopened.
+			 */
+			rel = relation_open(relid, AccessExclusiveLock);
+
+			newrelfilenumber = GetNewRelFileNumber(rel->rd_rel->reltablespace,
+												   NULL,
+												   rel->rd_rel->relpersistence);
+			RelationDropStorage(rel);
+
+			RelationAssumeNewRelfilelocator(rel);
+
+			/* Forget its ON COMMIT action */
+			remove_on_commit_action(relid);
+
+			/* Update its pg_temp_class entry */
+			tuple = GetPgTempClassTuple(relid);
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "could not find tuple for relation %u", relid);
+
+			form = (Form_pg_temp_class) GETSTRUCT(tuple);
+			form->relfilenode = newrelfilenumber;
+			form->relpages = 0;
+			form->reltuples = 0;
+			form->relallvisible = 0;
+			form->relallfrozen = 0;
+
+			UpdatePgTempClassTuple(relid, tuple);
+
+			heap_freetuple(tuple);
+
+			relation_close(rel, NoLock);
+
+			relids = lappend_oid(relids, relid);
+		}
+
+		/*
+		 * Make the pg_temp_class changes visible.  This will cause the
+		 * relcache entries to get updated, too.
+		 */
+		CommandCounterIncrement();
+
+		/*
+		 * Mark all the relcache entries for the relations whose storage we
+		 * deleted as invalid.  This will force a reload and reinitialize with
+		 * new storage the next time they are opened.
+		 */
+		foreach_oid(relid, relids)
+		{
+			RelationMarkInvalid(relid);
+		}
+
+		/*
+		 * Make note of the subtransaction ID in which we did this, so we can
+		 * track whether it survives to the end of the main transaction.
+		 */
+		if (discard_subid == InvalidSubTransactionId)
+			discard_subid = GetCurrentSubTransactionId();
+	}
+}
diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c
index 17d172df076..b4541ae2d1a 100644
--- a/src/backend/commands/discard.c
+++ b/src/backend/commands/discard.c
@@ -14,6 +14,7 @@
 #include "postgres.h"
 
 #include "access/xact.h"
+#include "catalog/global_temp.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/discard.h"
@@ -26,7 +27,7 @@
 static void DiscardAll(bool isTopLevel);
 
 /*
- * DISCARD { ALL | SEQUENCES | TEMP | PLANS }
+ * DISCARD { ALL | SEQUENCES | TEMP | PLANS | GLOBAL TEMP }
  */
 void
 DiscardCommand(DiscardStmt *stmt, bool isTopLevel)
@@ -49,6 +50,10 @@ DiscardCommand(DiscardStmt *stmt, bool isTopLevel)
 			ResetTempTableNamespace();
 			break;
 
+		case DISCARD_GLOBAL_TEMP:
+			DiscardGlobalTempRelations();
+			break;
+
 		default:
 			elog(ERROR, "unrecognized DISCARD target: %d", stmt->target);
 	}
@@ -76,4 +81,5 @@ DiscardAll(bool isTopLevel)
 	ResetPlanCache();
 	ResetTempTableNamespace();
 	ResetSequenceCaches();
+	DiscardGlobalTempRelations();
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f84bdb8dab9..86245a9ca01 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2162,7 +2162,7 @@ CheckPointStmt:
 
 /*****************************************************************************
  *
- * DISCARD { ALL | TEMP | PLANS | SEQUENCES }
+ * DISCARD { ALL | TEMP | PLANS | SEQUENCES | GLOBAL TEMP }
  *
  *****************************************************************************/
 
@@ -2202,6 +2202,20 @@ DiscardStmt:
 					n->target = DISCARD_SEQUENCES;
 					$$ = (Node *) n;
 				}
+			| DISCARD GLOBAL TEMP
+				{
+					DiscardStmt *n = makeNode(DiscardStmt);
+
+					n->target = DISCARD_GLOBAL_TEMP;
+					$$ = (Node *) n;
+				}
+			| DISCARD GLOBAL TEMPORARY
+				{
+					DiscardStmt *n = makeNode(DiscardStmt);
+
+					n->target = DISCARD_GLOBAL_TEMP;
+					$$ = (Node *) n;
+				}
 
 		;
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 4d33fcb5e9d..de4f36a1b86 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -2980,6 +2980,9 @@ CreateCommandTag(Node *parsetree)
 				case DISCARD_SEQUENCES:
 					tag = CMDTAG_DISCARD_SEQUENCES;
 					break;
+				case DISCARD_GLOBAL_TEMP:
+					tag = CMDTAG_DISCARD_GLOBAL_TEMP;
+					break;
 				default:
 					tag = CMDTAG_UNKNOWN;
 			}
diff --git a/src/backend/utils/cache/gtcatcache.c b/src/backend/utils/cache/gtcatcache.c
index 89f8be08543..de843b95bc3 100644
--- a/src/backend/utils/cache/gtcatcache.c
+++ b/src/backend/utils/cache/gtcatcache.c
@@ -1003,3 +1003,36 @@ AtEOSubXact_GTCatCache(bool isCommit, SubTransactionId mySubid,
 		/* Don't reset eoxact_list; we still need more cleanup later */
 	}
 }
+
+/*
+ * GTCatCacheDiscard
+ *
+ *	Discard all global temporary catalog cache entries.
+ */
+void
+GTCatCacheDiscard(void)
+{
+	/* Blow away the hash tables */
+	for (int cacheId = 0; cacheId < NUM_GT_CAT_CACHES; cacheId++)
+	{
+		GTCatCache *cache = &gt_cat_cache[cacheId];
+
+		if (cache->hashtable != NULL)
+		{
+			hash_destroy(cache->hashtable);
+			cache->hashtable = NULL;
+		}
+		cache->eoxact_list_len = 0;
+		cache->eoxact_list_overflowed = false;
+	}
+
+	/* Delete the tuple memory context */
+	if (gt_cat_cache_tupctx != NULL)
+	{
+		MemoryContextDelete(gt_cat_cache_tupctx);
+		gt_cat_cache_tupctx = NULL;
+	}
+
+	/* No entries to flush */
+	have_entries_to_flush = false;
+}
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 2611c2dc791..84caa46ac46 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -4390,7 +4390,7 @@ match_previous_words(int pattern_id,
 
 /* DISCARD */
 	else if (Matches("DISCARD"))
-		COMPLETE_WITH("ALL", "PLANS", "SEQUENCES", "TEMP");
+		COMPLETE_WITH("ALL", "GLOBAL TEMP", "PLANS", "SEQUENCES", "TEMP");
 
 /* DO */
 	else if (Matches("DO"))
diff --git a/src/include/catalog/global_temp.h b/src/include/catalog/global_temp.h
index df30a069817..db9243f6532 100644
--- a/src/include/catalog/global_temp.h
+++ b/src/include/catalog/global_temp.h
@@ -34,5 +34,6 @@ extern void AtEOSubXact_GlobalTempRelation(bool isCommit,
 extern bool IsGlobalTempRelationInUse(Oid relid);
 extern bool IsOtherUsingGlobalTempRelation(Oid relid);
 extern List *GetAllGlobalTempRelationsInUse(Oid dbId);
+extern void DiscardGlobalTempRelations(void);
 
 #endif							/* GLOBAL_TEMP_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 728ed56cb12..727e8aedcfc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -4193,6 +4193,7 @@ typedef enum DiscardMode
 	DISCARD_PLANS,
 	DISCARD_SEQUENCES,
 	DISCARD_TEMP,
+	DISCARD_GLOBAL_TEMP,
 } DiscardMode;
 
 typedef struct DiscardStmt
diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h
index befae5f6b4f..0123c8243a8 100644
--- a/src/include/tcop/cmdtaglist.h
+++ b/src/include/tcop/cmdtaglist.h
@@ -132,6 +132,7 @@ PG_CMDTAG(CMDTAG_DECLARE_CURSOR, "DECLARE CURSOR", false, false, false)
 PG_CMDTAG(CMDTAG_DELETE, "DELETE", false, false, true)
 PG_CMDTAG(CMDTAG_DISCARD, "DISCARD", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_ALL, "DISCARD ALL", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_GLOBAL_TEMP, "DISCARD GLOBAL TEMP", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_PLANS, "DISCARD PLANS", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_SEQUENCES, "DISCARD SEQUENCES", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_TEMP, "DISCARD TEMP", false, false, false)
diff --git a/src/include/utils/gtcatcache.h b/src/include/utils/gtcatcache.h
index edede00453b..b76911fd266 100644
--- a/src/include/utils/gtcatcache.h
+++ b/src/include/utils/gtcatcache.h
@@ -42,5 +42,6 @@ extern void GTCatCacheFlush(void);
 extern void AtEOXact_GTCatCache(bool isCommit);
 extern void AtEOSubXact_GTCatCache(bool isCommit, SubTransactionId mySubid,
 								   SubTransactionId parentSubid);
+extern void GTCatCacheDiscard(void);
 
 #endif							/* GTCATCACHE_H */
diff --git a/src/test/regress/expected/global_temp.out b/src/test/regress/expected/global_temp.out
index 26f6bc5b52d..67ef6a13a7f 100644
--- a/src/test/regress/expected/global_temp.out
+++ b/src/test/regress/expected/global_temp.out
@@ -1200,3 +1200,69 @@ SELECT tempfrozenxid::text::bigint - (SELECT min(relfrozenxid::text::bigint)
 (1 row)
 
 DROP TABLE tmp2;
+-- Test DISCARD GLOBAL TEMP
+\c
+SET search_path = global_temp_tests;
+INSERT INTO tmp1 VALUES (1, 'xxx'), (10, 'yyy');
+SELECT * FROM tmp1;
+ a  |  b  | c 
+----+-----+---
+  1 | xxx | 1
+ 10 | yyy | 2
+(2 rows)
+
+CREATE GLOBAL TEMP TABLE tmp2 (a int PRIMARY KEY, b text) PARTITION BY LIST (a);
+CREATE GLOBAL TEMP TABLE tmp2_p1 PARTITION OF tmp2 FOR VALUES IN (1);
+CREATE GLOBAL TEMP TABLE tmp2_p2 PARTITION OF tmp2 FOR VALUES IN (2);
+INSERT INTO tmp2 VALUES (1, 'Row 1'), (2, 'Row 2');
+SELECT tableoid::regclass, * FROM tmp2;
+ tableoid | a |   b   
+----------+---+-------
+ tmp2_p1  | 1 | Row 1
+ tmp2_p2  | 2 | Row 2
+(2 rows)
+
+DISCARD GLOBAL TEMP;
+SELECT tempfrozenxid, tempminmxid
+  FROM pg_stat_activity
+ WHERE pid = pg_backend_pid();
+ tempfrozenxid | tempminmxid 
+---------------+-------------
+               |            
+(1 row)
+
+SELECT relname, pg_relation_size(oid)
+  FROM pg_class
+ WHERE (relname ~ 'tmp1' OR relname ~ 'tmp2' OR relname ~ 'pg_temp_')
+   AND relpersistence = 'g' AND relkind IN ('r', 'p')
+ ORDER BY relname;
+          relname           | pg_relation_size 
+----------------------------+------------------
+ pg_temp_class              |                0
+ pg_temp_index              |                0
+ pg_temp_statistic          |                0
+ pg_temp_statistic_ext_data |                0
+ tmp1                       |                0
+ tmp2                       |                0
+ tmp2_p1                    |                0
+ tmp2_p2                    |                0
+(8 rows)
+
+SELECT * FROM tmp1;
+ a | b | c 
+---+---+---
+(0 rows)
+
+SELECT * FROM tmp2;
+ a | b 
+---+---
+(0 rows)
+
+INSERT INTO tmp1 VALUES (1, 'xxx'), (10, 'yyy');
+SELECT * FROM tmp1;
+ a  |  b  | c 
+----+-----+---
+  1 | xxx | 1
+ 10 | yyy | 2
+(2 rows)
+
diff --git a/src/test/regress/sql/global_temp.sql b/src/test/regress/sql/global_temp.sql
index 627db42040a..4d470d03f02 100644
--- a/src/test/regress/sql/global_temp.sql
+++ b/src/test/regress/sql/global_temp.sql
@@ -619,3 +619,29 @@ SELECT tempfrozenxid::text::bigint - (SELECT min(relfrozenxid::text::bigint)
  WHERE pid = pg_backend_pid();
 
 DROP TABLE tmp2;
+
+-- Test DISCARD GLOBAL TEMP
+\c
+SET search_path = global_temp_tests;
+INSERT INTO tmp1 VALUES (1, 'xxx'), (10, 'yyy');
+SELECT * FROM tmp1;
+CREATE GLOBAL TEMP TABLE tmp2 (a int PRIMARY KEY, b text) PARTITION BY LIST (a);
+CREATE GLOBAL TEMP TABLE tmp2_p1 PARTITION OF tmp2 FOR VALUES IN (1);
+CREATE GLOBAL TEMP TABLE tmp2_p2 PARTITION OF tmp2 FOR VALUES IN (2);
+INSERT INTO tmp2 VALUES (1, 'Row 1'), (2, 'Row 2');
+SELECT tableoid::regclass, * FROM tmp2;
+
+DISCARD GLOBAL TEMP;
+SELECT tempfrozenxid, tempminmxid
+  FROM pg_stat_activity
+ WHERE pid = pg_backend_pid();
+SELECT relname, pg_relation_size(oid)
+  FROM pg_class
+ WHERE (relname ~ 'tmp1' OR relname ~ 'tmp2' OR relname ~ 'pg_temp_')
+   AND relpersistence = 'g' AND relkind IN ('r', 'p')
+ ORDER BY relname;
+SELECT * FROM tmp1;
+SELECT * FROM tmp2;
+
+INSERT INTO tmp1 VALUES (1, 'xxx'), (10, 'yyy');
+SELECT * FROM tmp1;
-- 
2.43.0

