From f86de31f76790df40a0072dea65f79fe67adc338 Mon Sep 17 00:00:00 2001
From: rahila <rahilasyed.90@gmail.com>
Date: Wed, 12 Aug 2026 15:57:59 +0800
Subject: [PATCH] Replace ReleaseAllPlanCacheRefsInOwner calls with explicit
 ResourceOwnerRelease phases in plpgsql

plpgsql keeps three detached ResourceOwners (the procedure-lifespan
owner used for top-level CALLs, the DO-block simple-expression owner,
and the shared simple-expression owner) that must survive internal
COMMIT/ROLLBACK inside a procedure or DO block.  Each of them only
ever accumulates plan-cache refcounts, so they were drained via
ResourceOwnerReleaseAllOfKind() in ReleaseAllPlanCacheRefsInOwner()
before being deleted or reset.

This replaces those four call sites with direct calls to the public
ResourceOwnerRelease(), once per release phase (BEFORE_LOCKS, LOCKS,
AFTER_LOCKS), so the same plan-cache refcounts are released without
going through the single-kind function.

isCommit is passed as false at each call site.  ResourceOwnerRelease()
overloads isCommit as the "print leak warnings" flag for resources
still remembered when a phase runs; since these owners are expected to
be holding a live plan-cache reference at this point (that is the
resource being intentionally released here, not a leak), isCommit=true
makes every one of these releases emit a spurious "resource was not
closed" WARNING, which is visible to clients and breaks the plpgsql
regression tests' expected output.  isCommit=false suppresses that
warning path.

"make check" in src/pl/plpgsql and the full regression suite both pass
with no crashes or assertion failures.
---
 src/pl/plpgsql/src/pl_exec.c    |  6 +++++-
 src/pl/plpgsql/src/pl_handler.c | 12 +++++++++---
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 341beb496b..a328d5199d 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8838,7 +8838,11 @@ plpgsql_xact_cb(XactEvent event, void *arg)
 			FreeExecutorState(shared_simple_eval_estate);
 		shared_simple_eval_estate = NULL;
 		if (shared_simple_eval_resowner)
-			ReleaseAllPlanCacheRefsInOwner(shared_simple_eval_resowner);
+		{
+			ResourceOwnerRelease(shared_simple_eval_resowner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true);
+			ResourceOwnerRelease(shared_simple_eval_resowner, RESOURCE_RELEASE_LOCKS, false, true);
+			ResourceOwnerRelease(shared_simple_eval_resowner, RESOURCE_RELEASE_AFTER_LOCKS, false, true);
+		}
 		shared_simple_eval_resowner = NULL;
 	}
 	else if (event == XACT_EVENT_ABORT ||
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 3055c3db5d..0404f1b26a 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -289,7 +289,9 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
 		/* Be sure to release the procedure resowner if any */
 		if (procedure_resowner)
 		{
-			ReleaseAllPlanCacheRefsInOwner(procedure_resowner);
+			ResourceOwnerRelease(procedure_resowner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true);
+			ResourceOwnerRelease(procedure_resowner, RESOURCE_RELEASE_LOCKS, false, true);
+			ResourceOwnerRelease(procedure_resowner, RESOURCE_RELEASE_AFTER_LOCKS, false, true);
 			ResourceOwnerDelete(procedure_resowner);
 		}
 	}
@@ -393,7 +395,9 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
 
 		/* Clean up the private EState and resowner */
 		FreeExecutorState(simple_eval_estate);
-		ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
+		ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true);
+		ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_LOCKS, false, true);
+		ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_AFTER_LOCKS, false, true);
 		ResourceOwnerDelete(simple_eval_resowner);
 
 		/* Function should now have no remaining use-counts ... */
@@ -410,7 +414,9 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
 
 	/* Clean up the private EState and resowner */
 	FreeExecutorState(simple_eval_estate);
-	ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
+	ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true);
+	ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_LOCKS, false, true);
+	ResourceOwnerRelease(simple_eval_resowner, RESOURCE_RELEASE_AFTER_LOCKS, false, true);
 	ResourceOwnerDelete(simple_eval_resowner);
 
 	/* Function should now have no remaining use-counts ... */
-- 
2.39.5 (Apple Git-154)

