From 3f857611b69c95f325aba5ed8049e376326db8fd Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Mon, 22 Jun 2026 13:43:37 -0400
Subject: [PATCH v2 3/7] New function: stats_acquire_relation_lock().

Introduce a new funciton, stats_acquire_relation_lock() which will
perform the RangeVarGetRelidExtended() call used to verify the correct
reloid of the relation, verify that the caller has the correct
permissions for the operation, and acquiring the lock.

Additionally, it will check RecoveryInProgress() before acquiring a lock
because we can't acquire locks during recovery, let alone set
statistics.

This function will be used by all of the callers of
relation_statistics_update() and attribute_statistics_update().
---
 src/include/statistics/stat_utils.h |  2 ++
 src/backend/statistics/stat_utils.c | 26 ++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h
index 74da7790579..bcdfa616ce6 100644
--- a/src/include/statistics/stat_utils.h
+++ b/src/include/statistics/stat_utils.h
@@ -37,6 +37,8 @@ extern bool stats_check_arg_pair(FunctionCallInfo fcinfo,
 extern void RangeVarCallbackForStats(const RangeVar *relation,
 									 Oid relId, Oid oldRelId, void *arg);
 
+extern Oid stats_acquire_relation_lock(const char *nspname, const char *relname);
+
 extern bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo,
 											 FunctionCallInfo positional_fcinfo,
 											 struct StatsArgInfo *arginfo);
diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c
index a673e3c704b..75792ff966a 100644
--- a/src/backend/statistics/stat_utils.c
+++ b/src/backend/statistics/stat_utils.c
@@ -26,6 +26,7 @@
 #include "catalog/pg_statistic.h"
 #include "funcapi.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "statistics/stat_utils.h"
 #include "storage/lmgr.h"
@@ -753,3 +754,28 @@ statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited,
 		nulls[Anum_pg_statistic_stacoll1 + slotnum - 1] = false;
 	}
 }
+
+/*
+ * Convenience routine to encapsulate the RangeVarGetRelidExtended()
+ * that all external callers must make before calling
+ * relation_statistics_update() or attribute_statistics_update().
+ *
+ * Check for recovery in progress before acquiring any locks.
+ */
+Oid
+stats_acquire_relation_lock(const char *nspname, const char *relname)
+{
+	Oid		reloid;
+	Oid		locked_table = InvalidOid;
+
+	if (RecoveryInProgress())
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("recovery is in progress"),
+				 errhint("Statistics cannot be modified during recovery.")));
+
+	reloid = RangeVarGetRelidExtended(makeRangeVar((char *) nspname, (char *) relname, -1),
+									  ShareUpdateExclusiveLock, 0,
+									  RangeVarCallbackForStats, &locked_table);
+	return reloid;
+}
-- 
2.54.0

