From db9b5e1304fd4ddadff2eae0359ea5e7a48ffbc6 Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Mon, 24 Aug 2026 23:38:53 +1200
Subject: [PATCH] RFC: Add BUG_WARNING elevel

We really should be alerted more loudly to certain elog/ereport WARNINGs.
pg_regress wouldn't miss any WARNINGs that were not expected, but the
TAP tests could.  Here we define BUG_WARNING, which is the same as
WARNING on production builds, but gets promoted to ERROR in
assert-enabled builds.  The idea is that WARNINGs that we really don't
expect to get can be adjusted to use BUG_WARNING instead.

This also adjusts a select few such elog calls to demonstrate.

Patch-grade: REQUEST FOR COMMENTS ONLY
---
 src/backend/utils/mmgr/aset.c                 |  18 +-
 src/backend/utils/mmgr/bump.c                 |   6 +-
 src/backend/utils/mmgr/generation.c           |  16 +-
 src/backend/utils/mmgr/slab.c                 |  18 +-
 src/backend/utils/resowner/resowner.c         |   2 +-
 src/include/utils/elog.h                      |  12 ++
 .../expected/test_resowner_1.out              | 192 ++++++++++++++++++
 .../expected/test_resowner_2.out              | 192 ++++++++++++++++++
 8 files changed, 426 insertions(+), 30 deletions(-)
 create mode 100644 src/test/modules/test_resowner/expected/test_resowner_1.out
 create mode 100644 src/test/modules/test_resowner/expected/test_resowner_2.out

diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 6a9ea367107..626941a79f1 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -1706,7 +1706,7 @@ AllocSetCheck(MemoryContext context)
 		if (!blk_used)
 		{
 			if (!IsKeeperBlock(set, block))
-				elog(WARNING, "problem in alloc set %s: empty block %p",
+				elog(BUG_WARNING, "problem in alloc set %s: empty block %p",
 					 name, block);
 		}
 
@@ -1717,7 +1717,7 @@ AllocSetCheck(MemoryContext context)
 			block->prev != prevblock ||
 			block->freeptr < bpoz ||
 			block->freeptr > block->endptr)
-			elog(WARNING, "problem in alloc set %s: corrupt header in block %p",
+			elog(BUG_WARNING, "problem in alloc set %s: corrupt header in block %p",
 				 name, block);
 
 		/*
@@ -1739,7 +1739,7 @@ AllocSetCheck(MemoryContext context)
 
 				/* make sure this chunk consumes the entire block */
 				if (chsize + ALLOC_CHUNKHDRSZ != blk_used)
-					elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
+					elog(BUG_WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
 						 name, chunk, block);
 			}
 			else
@@ -1747,7 +1747,7 @@ AllocSetCheck(MemoryContext context)
 				int			fidx = MemoryChunkGetValue(chunk);
 
 				if (!FreeListIdxIsValid(fidx))
-					elog(WARNING, "problem in alloc set %s: bad chunk size for chunk %p in block %p",
+					elog(BUG_WARNING, "problem in alloc set %s: bad chunk size for chunk %p in block %p",
 						 name, chunk, block);
 
 				chsize = GetChunkSizeFromFreeListIdx(fidx); /* aligned chunk size */
@@ -1757,7 +1757,7 @@ AllocSetCheck(MemoryContext context)
 				 * block.
 				 */
 				if (block != MemoryChunkGetBlock(chunk))
-					elog(WARNING, "problem in alloc set %s: bad block offset for chunk %p in block %p",
+					elog(BUG_WARNING, "problem in alloc set %s: bad block offset for chunk %p in block %p",
 						 name, chunk, block);
 			}
 			dsize = chunk->requested_size;	/* real data */
@@ -1769,7 +1769,7 @@ AllocSetCheck(MemoryContext context)
 
 			/* chsize must not be smaller than the first freelist's size */
 			if (chsize < (1 << ALLOC_MINBITS))
-				elog(WARNING, "problem in alloc set %s: bad size %zu for chunk %p in block %p",
+				elog(BUG_WARNING, "problem in alloc set %s: bad size %zu for chunk %p in block %p",
 					 name, chsize, chunk, block);
 
 			/*
@@ -1777,7 +1777,7 @@ AllocSetCheck(MemoryContext context)
 			 */
 			if (dsize != InvalidAllocSize && dsize < chsize &&
 				!sentinel_ok(chunk, ALLOC_CHUNKHDRSZ + dsize))
-				elog(WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p",
+				elog(BUG_WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p",
 					 name, block, chunk);
 
 			/* if chunk is allocated, disallow access to the chunk header */
@@ -1791,11 +1791,11 @@ AllocSetCheck(MemoryContext context)
 		}
 
 		if ((blk_data + (nchunks * ALLOC_CHUNKHDRSZ)) != blk_used)
-			elog(WARNING, "problem in alloc set %s: found inconsistent memory block %p",
+			elog(BUG_WARNING, "problem in alloc set %s: found inconsistent memory block %p",
 				 name, block);
 
 		if (has_external_chunk && nchunks > 1)
-			elog(WARNING, "problem in alloc set %s: external chunk on non-dedicated block %p",
+			elog(BUG_WARNING, "problem in alloc set %s: external chunk on non-dedicated block %p",
 				 name, block);
 	}
 
diff --git a/src/backend/utils/mmgr/bump.c b/src/backend/utils/mmgr/bump.c
index 9bb579935db..8f46be180fe 100644
--- a/src/backend/utils/mmgr/bump.c
+++ b/src/backend/utils/mmgr/bump.c
@@ -786,7 +786,7 @@ BumpCheck(MemoryContext context)
 
 		/* check block belongs to the correct context */
 		if (block->context != bump)
-			elog(WARNING, "problem in Bump %s: bogus context link in block %p",
+			elog(BUG_WARNING, "problem in Bump %s: bogus context link in block %p",
 				 name, block);
 
 		/* now walk through the chunks and count them */
@@ -821,12 +821,12 @@ BumpCheck(MemoryContext context)
 
 			/* chunks have both block and context pointers, so check both */
 			if (chunkblock != block)
-				elog(WARNING, "problem in Bump %s: bogus block link in block %p, chunk %p",
+				elog(BUG_WARNING, "problem in Bump %s: bogus block link in block %p, chunk %p",
 					 name, block, chunk);
 		}
 
 		if (has_external_chunk && nchunks > 1)
-			elog(WARNING, "problem in Bump %s: external chunk on non-dedicated block %p",
+			elog(BUG_WARNING, "problem in Bump %s: external chunk on non-dedicated block %p",
 				 name, block);
 
 	}
diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c
index 609c9bdc9a6..c17da92a25c 100644
--- a/src/backend/utils/mmgr/generation.c
+++ b/src/backend/utils/mmgr/generation.c
@@ -1152,12 +1152,12 @@ GenerationCheck(MemoryContext context)
 		 * might completely empty if it's the freeblock.
 		 */
 		if (block->nfree > block->nchunks)
-			elog(WARNING, "problem in Generation %s: number of free chunks %d in block %p exceeds %d allocated",
+			elog(BUG_WARNING, "problem in Generation %s: number of free chunks %d in block %p exceeds %d allocated",
 				 name, block->nfree, block, block->nchunks);
 
 		/* check block belongs to the correct context */
 		if (block->context != gen)
-			elog(WARNING, "problem in Generation %s: bogus context link in block %p",
+			elog(BUG_WARNING, "problem in Generation %s: bogus context link in block %p",
 				 name, block);
 
 		/* Now walk through the chunks and count them. */
@@ -1193,7 +1193,7 @@ GenerationCheck(MemoryContext context)
 
 			/* chunks have both block and context pointers, so check both */
 			if (chunkblock != block)
-				elog(WARNING, "problem in Generation %s: bogus block link in block %p, chunk %p",
+				elog(BUG_WARNING, "problem in Generation %s: bogus block link in block %p, chunk %p",
 					 name, block, chunk);
 
 
@@ -1203,13 +1203,13 @@ GenerationCheck(MemoryContext context)
 				/* now make sure the chunk size is correct */
 				if (chunksize < chunk->requested_size ||
 					chunksize != MAXALIGN(chunksize))
-					elog(WARNING, "problem in Generation %s: bogus chunk size in block %p, chunk %p",
+					elog(BUG_WARNING, "problem in Generation %s: bogus chunk size in block %p, chunk %p",
 						 name, block, chunk);
 
 				/* check sentinel */
 				Assert(chunk->requested_size < chunksize);
 				if (!sentinel_ok(chunk, Generation_CHUNKHDRSZ + chunk->requested_size))
-					elog(WARNING, "problem in Generation %s: detected write past chunk end in block %p, chunk %p",
+					elog(BUG_WARNING, "problem in Generation %s: detected write past chunk end in block %p, chunk %p",
 						 name, block, chunk);
 			}
 			else
@@ -1225,15 +1225,15 @@ GenerationCheck(MemoryContext context)
 		 * (as tracked in the block header).
 		 */
 		if (nchunks != block->nchunks)
-			elog(WARNING, "problem in Generation %s: number of allocated chunks %d in block %p does not match header %d",
+			elog(BUG_WARNING, "problem in Generation %s: number of allocated chunks %d in block %p does not match header %d",
 				 name, nchunks, block, block->nchunks);
 
 		if (nfree != block->nfree)
-			elog(WARNING, "problem in Generation %s: number of free chunks %d in block %p does not match header %d",
+			elog(BUG_WARNING, "problem in Generation %s: number of free chunks %d in block %p does not match header %d",
 				 name, nfree, block, block->nfree);
 
 		if (has_external_chunk && nchunks > 1)
-			elog(WARNING, "problem in Generation %s: external chunk on non-dedicated block %p",
+			elog(BUG_WARNING, "problem in Generation %s: external chunk on non-dedicated block %p",
 				 name, block);
 
 	}
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index 2ad325547fd..cf830432908 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -1054,7 +1054,7 @@ SlabCheck(MemoryContext context)
 		SlabBlock  *block = dlist_container(SlabBlock, node, iter.cur);
 
 		if (block->nfree != slab->chunksPerBlock)
-			elog(WARNING, "problem in slab %s: empty block %p should have %d free chunks but has %d chunks free",
+			elog(BUG_WARNING, "problem in slab %s: empty block %p should have %d free chunks but has %d chunks free",
 				 name, block, slab->chunksPerBlock, block->nfree);
 	}
 
@@ -1075,17 +1075,17 @@ SlabCheck(MemoryContext context)
 			 * matches the position in the blocklist.
 			 */
 			if (SlabBlocklistIndex(slab, block->nfree) != i)
-				elog(WARNING, "problem in slab %s: block %p is on blocklist %d but should be on blocklist %d",
+				elog(BUG_WARNING, "problem in slab %s: block %p is on blocklist %d but should be on blocklist %d",
 					 name, block, i, SlabBlocklistIndex(slab, block->nfree));
 
 			/* make sure the block is not empty */
 			if (block->nfree >= slab->chunksPerBlock)
-				elog(WARNING, "problem in slab %s: empty block %p incorrectly stored on blocklist element %d",
+				elog(BUG_WARNING, "problem in slab %s: empty block %p incorrectly stored on blocklist element %d",
 					 name, block, i);
 
 			/* make sure the slab pointer correctly points to this context */
 			if (block->slab != slab)
-				elog(WARNING, "problem in slab %s: bogus slab link in block %p",
+				elog(BUG_WARNING, "problem in slab %s: bogus slab link in block %p",
 					 name, block);
 
 			/* reset the array of free chunks for this block */
@@ -1105,7 +1105,7 @@ SlabCheck(MemoryContext context)
 				if (cur_chunk < SlabBlockGetChunk(slab, block, 0) ||
 					cur_chunk > SlabBlockGetChunk(slab, block, slab->chunksPerBlock - 1) ||
 					SlabChunkMod(slab, block, cur_chunk) != 0)
-					elog(WARNING, "problem in slab %s: bogus free list link %p in block %p",
+					elog(BUG_WARNING, "problem in slab %s: bogus free list link %p in block %p",
 						 name, cur_chunk, block);
 
 				/* count the chunk and mark it free on the free chunk array */
@@ -1120,7 +1120,7 @@ SlabCheck(MemoryContext context)
 			/* check that the unused pointer matches what nunused claims */
 			if (SlabBlockGetChunk(slab, block, slab->chunksPerBlock - block->nunused) !=
 				block->unused)
-				elog(WARNING, "problem in slab %s: mismatch detected between nunused chunks and unused pointer in block %p",
+				elog(BUG_WARNING, "problem in slab %s: mismatch detected between nunused chunks and unused pointer in block %p",
 					 name, block);
 
 			/*
@@ -1162,13 +1162,13 @@ SlabCheck(MemoryContext context)
 					 * the block
 					 */
 					if (chunkblock != block)
-						elog(WARNING, "problem in slab %s: bogus block link in block %p, chunk %p",
+						elog(BUG_WARNING, "problem in slab %s: bogus block link in block %p, chunk %p",
 							 name, block, chunk);
 
 					/* check the sentinel byte is intact */
 					Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ));
 					if (!sentinel_ok(chunk, Slab_CHUNKHDRSZ + slab->chunkSize))
-						elog(WARNING, "problem in slab %s: detected write past chunk end in block %p, chunk %p",
+						elog(BUG_WARNING, "problem in slab %s: detected write past chunk end in block %p, chunk %p",
 							 name, block, chunk);
 				}
 			}
@@ -1178,7 +1178,7 @@ SlabCheck(MemoryContext context)
 			 * in the block header).
 			 */
 			if (nfree != block->nfree)
-				elog(WARNING, "problem in slab %s: nfree in block %p is %d but %d chunk were found as free",
+				elog(BUG_WARNING, "problem in slab %s: nfree in block %p is %d but %d chunk were found as free",
 					 name, block, block->nfree, nfree);
 
 			nblocks++;
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index ac413d54837..8dac4a91019 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -392,7 +392,7 @@ ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase,
 			res_str = kind->DebugPrint ?
 				kind->DebugPrint(value)
 				: psprintf("%s %p", kind->name, DatumGetPointer(value));
-			elog(WARNING, "resource was not closed: %s", res_str);
+			elog(BUG_WARNING, "resource was not closed: %s", res_str);
 			pfree(res_str);
 		}
 
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 6ae376ba001..6356f2093ba 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -57,6 +57,18 @@ struct Node;
 #define FATAL_CLIENT_ONLY 23	/* fatal version of WARNING_CLIENT_ONLY */
 #define PANIC		24			/* take down the other backends with me */
 
+/*
+ * Some elog/ereports that we report a WARNING for are likely to be caused by
+ * buggy code.  These may go unnoticed by some of our test suites (e.g. TAP
+ * tests).  Here we define a macro which can be used in selected places where
+ * we don't want the given WARNING to not be noticed.
+ */
+#ifdef USE_ASSERT_CHECKING
+#define BUG_WARNING		ERROR
+#else
+#define BUG_WARNING		WARNING
+#endif
+
 /*
  * NOTE: the alternate names PGWARNING and PGERROR are useful for dealing
  * with third-party headers that make other definitions of WARNING and/or
diff --git a/src/test/modules/test_resowner/expected/test_resowner_1.out b/src/test/modules/test_resowner/expected/test_resowner_1.out
new file mode 100644
index 00000000000..c11255c83c8
--- /dev/null
+++ b/src/test/modules/test_resowner/expected/test_resowner_1.out
@@ -0,0 +1,192 @@
+CREATE EXTENSION test_resowner;
+-- This is small enough that everything fits in the small array
+SELECT test_resowner_priorities(2, 3);
+NOTICE:  releasing resources before locks
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 2
+ test_resowner_priorities 
+--------------------------
+ 
+(1 row)
+
+-- Same test with more resources, to exercise the hash table
+SELECT test_resowner_priorities(2, 32);
+NOTICE:  releasing resources before locks
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+ test_resowner_priorities 
+--------------------------
+ 
+(1 row)
+
+-- Basic test with lots more resources, to test extending the hash table
+SELECT test_resowner_many(
+  3,      -- # of different resource kinds
+  100000, -- before-locks resources to remember
+  500,    -- before-locks resources to forget
+  100000, -- after-locks resources to remember
+  500     -- after-locks resources to forget
+);
+NOTICE:  remembering 100000 before-locks resources
+NOTICE:  remembering 100000 after-locks resources
+NOTICE:  forgetting 500 before-locks resources
+NOTICE:  forgetting 500 after-locks resources
+NOTICE:  releasing resources before locks
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+ test_resowner_many 
+--------------------
+ 
+(1 row)
+
+-- Test resource leak warning
+SELECT test_resowner_leak();
+NOTICE:  releasing string: my string
+ERROR:  resource was not closed: test string "my string"
+-- Negative tests, using a resource owner after release-phase has started.
+set client_min_messages='warning'; -- order between ERROR and NOTICE varies
+SELECT test_resowner_remember_between_phases();
+ERROR:  ResourceOwnerEnlarge called after release started
+SELECT test_resowner_forget_between_phases();
+ERROR:  ResourceOwnerForget called for test resource after release started
+reset client_min_messages;
diff --git a/src/test/modules/test_resowner/expected/test_resowner_2.out b/src/test/modules/test_resowner/expected/test_resowner_2.out
new file mode 100644
index 00000000000..e091713b04a
--- /dev/null
+++ b/src/test/modules/test_resowner/expected/test_resowner_2.out
@@ -0,0 +1,192 @@
+CREATE EXTENSION test_resowner;
+-- This is small enough that everything fits in the small array
+SELECT test_resowner_priorities(2, 3);
+NOTICE:  releasing resources before locks
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 2
+ test_resowner_priorities 
+--------------------------
+ 
+(1 row)
+
+-- Same test with more resources, to exercise the hash table
+SELECT test_resowner_priorities(2, 32);
+NOTICE:  releasing resources before locks
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 1
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: child before locks priority 2
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 1
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing string: parent before locks priority 2
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 1
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: child after locks priority 2
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 1
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+NOTICE:  releasing string: parent after locks priority 2
+ test_resowner_priorities 
+--------------------------
+ 
+(1 row)
+
+-- Basic test with lots more resources, to test extending the hash table
+SELECT test_resowner_many(
+  3,      -- # of different resource kinds
+  100000, -- before-locks resources to remember
+  500,    -- before-locks resources to forget
+  100000, -- after-locks resources to remember
+  500     -- after-locks resources to forget
+);
+NOTICE:  remembering 100000 before-locks resources
+NOTICE:  remembering 100000 after-locks resources
+NOTICE:  forgetting 500 before-locks resources
+NOTICE:  forgetting 500 after-locks resources
+NOTICE:  releasing resources before locks
+NOTICE:  releasing locks
+NOTICE:  releasing resources after locks
+ test_resowner_many 
+--------------------
+ 
+(1 row)
+
+-- Test resource leak warning
+SELECT test_resowner_leak();
+ERROR:  resource was not closed: test string "my string"
+NOTICE:  releasing string: my string
+-- Negative tests, using a resource owner after release-phase has started.
+set client_min_messages='warning'; -- order between ERROR and NOTICE varies
+SELECT test_resowner_remember_between_phases();
+ERROR:  ResourceOwnerEnlarge called after release started
+SELECT test_resowner_forget_between_phases();
+ERROR:  ResourceOwnerForget called for test resource after release started
+reset client_min_messages;
-- 
2.53.0

