0001-Re-introduce-pgstat_drop_entry-keeping-ABI-compatibi.patch

text/plain

Filename: 0001-Re-introduce-pgstat_drop_entry-keeping-ABI-compatibi.patch
Type: text/plain
Part: 0
Message: Re: BUG #19520: PANIC when concurrently manipulating stored procedures with pg_stat_statements and track_functions =

Patch

Format: format-patch
Series: patch 0001
Subject: Re-introduce pgstat_drop_entry(), keeping ABI compatibility
File+
.abi-compliance-history 1 1
src/backend/utils/activity/pgstat.c 1 1
src/backend/utils/activity/pgstat_function.c 2 2
src/backend/utils/activity/pgstat_replslot.c 2 2
src/backend/utils/activity/pgstat_shmem.c 14 3
src/backend/utils/activity/pgstat_xact.c 4 4
src/include/utils/pgstat_internal.h 3 2
src/test/modules/injection_points/injection_stats.c 2 2
From 03e073d2f1d22e777baf62ea2fa8293df76465c4 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Sat, 20 Jun 2026 21:11:05 +0900
Subject: [PATCH] Re-introduce pgstat_drop_entry(), keeping ABI compatibility

This routine acts as a wrapper of a new pgstat_drop_entry_ext(), used in
the core code with the new missing_ok argument.

Backpatch-through: 15-18
---
 src/include/utils/pgstat_internal.h             |  5 +++--
 src/backend/utils/activity/pgstat.c             |  2 +-
 src/backend/utils/activity/pgstat_function.c    |  4 ++--
 src/backend/utils/activity/pgstat_replslot.c    |  4 ++--
 src/backend/utils/activity/pgstat_shmem.c       | 17 ++++++++++++++---
 src/backend/utils/activity/pgstat_xact.c        |  8 ++++----
 .../modules/injection_points/injection_stats.c  |  4 ++--
 .abi-compliance-history                         |  2 +-
 8 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 4f840c38f072..c09eda3a84d9 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -708,8 +708,9 @@ extern PgStat_EntryRef *pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64
 extern bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait);
 extern bool pgstat_lock_entry_shared(PgStat_EntryRef *entry_ref, bool nowait);
 extern void pgstat_unlock_entry(PgStat_EntryRef *entry_ref);
-extern bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid,
-							  bool missing_ok);
+extern bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid);
+extern bool pgstat_drop_entry_ext(PgStat_Kind kind, Oid dboid, uint64 objid,
+								  bool missing_ok);
 extern void pgstat_drop_all_entries(void);
 extern void pgstat_drop_matching_entries(bool (*do_drop) (PgStatShared_HashEntry *, Datum),
 										 Datum match_data);
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index d997be2e1d93..99e537bc886a 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -620,7 +620,7 @@ pgstat_shutdown_hook(int code, Datum arg)
 	dlist_init(&pgStatPending);
 
 	/* drop the backend stats entry */
-	if (!pgstat_drop_entry(PGSTAT_KIND_BACKEND, InvalidOid, MyProcNumber, false))
+	if (!pgstat_drop_entry_ext(PGSTAT_KIND_BACKEND, InvalidOid, MyProcNumber, false))
 		pgstat_request_entry_refs_gc();
 
 	pgstat_detach_shmem();
diff --git a/src/backend/utils/activity/pgstat_function.c b/src/backend/utils/activity/pgstat_function.c
index f763a0d6f5ba..eaeb0dcb1def 100644
--- a/src/backend/utils/activity/pgstat_function.c
+++ b/src/backend/utils/activity/pgstat_function.c
@@ -112,8 +112,8 @@ pgstat_init_function_usage(FunctionCallInfo fcinfo,
 		AcceptInvalidationMessages();
 		if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid)))
 		{
-			pgstat_drop_entry(PGSTAT_KIND_FUNCTION, MyDatabaseId,
-							  fcinfo->flinfo->fn_oid, true);
+			pgstat_drop_entry_ext(PGSTAT_KIND_FUNCTION, MyDatabaseId,
+								  fcinfo->flinfo->fn_oid, true);
 			ereport(ERROR, errcode(ERRCODE_UNDEFINED_FUNCTION),
 					errmsg("function call to dropped function"));
 		}
diff --git a/src/backend/utils/activity/pgstat_replslot.c b/src/backend/utils/activity/pgstat_replslot.c
index 746b97a0b5af..675c535266c0 100644
--- a/src/backend/utils/activity/pgstat_replslot.c
+++ b/src/backend/utils/activity/pgstat_replslot.c
@@ -157,8 +157,8 @@ pgstat_drop_replslot(ReplicationSlot *slot)
 {
 	Assert(LWLockHeldByMeInMode(ReplicationSlotAllocationLock, LW_EXCLUSIVE));
 
-	if (!pgstat_drop_entry(PGSTAT_KIND_REPLSLOT, InvalidOid,
-						   ReplicationSlotIndex(slot), false))
+	if (!pgstat_drop_entry_ext(PGSTAT_KIND_REPLSLOT, InvalidOid,
+							   ReplicationSlotIndex(slot), false))
 		pgstat_request_entry_refs_gc();
 }
 
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 414b66be2dc4..056c24c6ee1b 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -880,7 +880,7 @@ pgstat_free_entry(PgStatShared_HashEntry *shent, dshash_seq_status *hstat)
 
 /*
  * Helper for both pgstat_drop_database_and_contents() and
- * pgstat_drop_entry(). If hstat is non-null delete the shared entry using
+ * pgstat_drop_entry_ext(). If hstat is non-null delete the shared entry using
  * dshash_delete_current(), otherwise use dshash_delete_entry(). In either
  * case the entry needs to be already locked.
  */
@@ -968,6 +968,17 @@ pgstat_drop_database_and_contents(Oid dboid)
 		pgstat_request_entry_refs_gc();
 }
 
+/*
+ * ABI-preserving wrapper around pgstat_drop_entry_ext().
+ *
+ * The original routine introduced in v15 did not include "missing_ok".
+ */
+bool
+pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
+{
+	return pgstat_drop_entry_ext(kind, dboid, objid, false);
+}
+
 /*
  * Drop a single stats entry.
  *
@@ -982,8 +993,8 @@ pgstat_drop_database_and_contents(Oid dboid)
  * pgstat_gc_entry_refs().
  */
 bool
-pgstat_drop_entry(PgStat_Kind kind, Oid dboid, uint64 objid,
-				  bool missing_ok)
+pgstat_drop_entry_ext(PgStat_Kind kind, Oid dboid, uint64 objid,
+					  bool missing_ok)
 {
 	PgStat_HashKey key;
 	PgStatShared_HashEntry *shent;
diff --git a/src/backend/utils/activity/pgstat_xact.c b/src/backend/utils/activity/pgstat_xact.c
index b058c978dcf3..fbbf2844a58f 100644
--- a/src/backend/utils/activity/pgstat_xact.c
+++ b/src/backend/utils/activity/pgstat_xact.c
@@ -85,7 +85,7 @@ AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
 			 * Transaction that dropped an object committed. Drop the stats
 			 * too.
 			 */
-			if (!pgstat_drop_entry(it->kind, it->dboid, objid, true))
+			if (!pgstat_drop_entry_ext(it->kind, it->dboid, objid, true))
 				not_freed_count++;
 		}
 		else if (!isCommit && pending->is_create)
@@ -94,7 +94,7 @@ AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
 			 * Transaction that created an object aborted. Drop the stats
 			 * associated with the object.
 			 */
-			if (!pgstat_drop_entry(it->kind, it->dboid, objid, true))
+			if (!pgstat_drop_entry_ext(it->kind, it->dboid, objid, true))
 				not_freed_count++;
 		}
 
@@ -160,7 +160,7 @@ AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
 			 * Subtransaction creating a new stats object aborted. Drop the
 			 * stats object.
 			 */
-			if (!pgstat_drop_entry(it->kind, it->dboid, objid, true))
+			if (!pgstat_drop_entry_ext(it->kind, it->dboid, objid, true))
 				not_freed_count++;
 			pfree(pending);
 		}
@@ -323,7 +323,7 @@ pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items,
 		xl_xact_stats_item *it = &items[i];
 		uint64		objid = ((uint64) it->objid_hi) << 32 | it->objid_lo;
 
-		if (!pgstat_drop_entry(it->kind, it->dboid, objid, true))
+		if (!pgstat_drop_entry_ext(it->kind, it->dboid, objid, true))
 			not_freed_count++;
 	}
 
diff --git a/src/test/modules/injection_points/injection_stats.c b/src/test/modules/injection_points/injection_stats.c
index 435a0484a4ba..c659b2660d4f 100644
--- a/src/test/modules/injection_points/injection_stats.c
+++ b/src/test/modules/injection_points/injection_stats.c
@@ -149,8 +149,8 @@ pgstat_drop_inj(const char *name)
 	if (!inj_stats_loaded || !inj_stats_enabled)
 		return;
 
-	if (!pgstat_drop_entry(PGSTAT_KIND_INJECTION, InvalidOid,
-						   PGSTAT_INJ_IDX(name), false))
+	if (!pgstat_drop_entry_ext(PGSTAT_KIND_INJECTION, InvalidOid,
+							   PGSTAT_INJ_IDX(name), false))
 		pgstat_request_entry_refs_gc();
 }
 
diff --git a/.abi-compliance-history b/.abi-compliance-history
index 6ba3e7519b70..bff1286f9ddd 100644
--- a/.abi-compliance-history
+++ b/.abi-compliance-history
@@ -23,7 +23,7 @@
 # Fix PANIC with track_functions due to concurrent drop of pgstats entries
 # 2026-06-18 11:49:34 +0900
 #
-# This commit has added a "missing_ok" argument to pgstat_drop_entry().  All
+# This commit has added a "missing_ok" argument to pgstat_drop_entry_ext().  All
 # the callers of this routine are in core for v15-v17.  One custom stats kinds
 # available in the public since v18 is impacted (maintainer informed).
 
-- 
2.54.0