From 79564c6211d7dd8f80062d9acbcea20969698803 Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Mon, 22 Jun 2026 14:48:12 -0400
Subject: [PATCH v2 7/7] Make callers of update_attstats() use
 stats_acquire_relation_lock().

This is the same change that was made in relation_stats.c, but with the
function renaming already done beforehand.
---
 src/backend/statistics/attribute_stats.c | 109 +++++++++++------------
 1 file changed, 51 insertions(+), 58 deletions(-)

diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index 7dccce83c65..f903d2c0003 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -33,8 +33,7 @@
 #include "utils/syscache.h"
 
 /*
- * Positional argument numbers, names, and types for
- * update_attstats() and pg_restore_attribute_stats().
+ * Positional argument numbers, names, and types for update_attstats()
  */
 
 enum attribute_stats_argnum
@@ -106,7 +105,7 @@ static struct StatsArgInfo cleararginfo[] =
 	[C_NUM_ATTRIBUTE_STATS_ARGS] = {0}
 };
 
-static bool update_attstats(FunctionCallInfo fcinfo);
+static bool update_attstats(Oid reloid, FunctionCallInfo fcinfo);
 static void upsert_pg_statistic(Relation starel, HeapTuple oldtup,
 								const Datum *values, const bool *nulls, const bool *replaces);
 static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit);
@@ -128,15 +127,12 @@ static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit);
  * and other statistic kinds may still be updated.
  */
 static bool
-update_attstats(FunctionCallInfo fcinfo)
+update_attstats(Oid reloid, FunctionCallInfo fcinfo)
 {
-	char	   *nspname;
 	char	   *relname;
-	Oid			reloid;
 	char	   *attname;
 	AttrNumber	attnum;
 	bool		inherited;
-	Oid			locked_table = InvalidOid;
 
 	Relation	starel;
 	HeapTuple	statup;
@@ -173,20 +169,8 @@ update_attstats(FunctionCallInfo fcinfo)
 	stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG);
 	stats_check_required_arg(fcinfo, attarginfo, ATTRELNAME_ARG);
 
-	nspname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELSCHEMA_ARG));
 	relname = TextDatumGetCString(PG_GETARG_DATUM(ATTRELNAME_ARG));
 
-	if (RecoveryInProgress())
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-				 errmsg("recovery is in progress"),
-				 errhint("Statistics cannot be modified during recovery.")));
-
-	/* lock before looking up attribute */
-	reloid = RangeVarGetRelidExtended(makeRangeVar(nspname, relname, -1),
-									  ShareUpdateExclusiveLock, 0,
-									  RangeVarCallbackForStats, &locked_table);
-
 	/* user can specify either attname or attnum, but not both */
 	if (!PG_ARGISNULL(ATTNAME_ARG))
 	{
@@ -605,7 +589,6 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
 	char	   *attname;
 	AttrNumber	attnum;
 	bool		inherited;
-	Oid			locked_table = InvalidOid;
 
 	stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELSCHEMA_ARG);
 	stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELNAME_ARG);
@@ -614,16 +597,7 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
 
 	nspname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELSCHEMA_ARG));
 	relname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTRELNAME_ARG));
-
-	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(nspname, relname, -1),
-									  ShareUpdateExclusiveLock, 0,
-									  RangeVarCallbackForStats, &locked_table);
+	reloid = stats_acquire_relation_lock(nspname, relname);
 
 	attname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTNAME_ARG));
 	attnum = get_attnum(reloid, attname);
@@ -677,6 +651,9 @@ pg_restore_attribute_stats(PG_FUNCTION_ARGS)
 {
 	LOCAL_FCINFO(positional_fcinfo, NUM_ATTRIBUTE_STATS_ARGS);
 	bool		result = true;
+	Oid			reloid;
+	char	   *nspname;
+	char	   *relname;
 
 	InitFunctionCallInfoData(*positional_fcinfo, NULL, NUM_ATTRIBUTE_STATS_ARGS,
 							 InvalidOid, NULL, NULL);
@@ -685,7 +662,15 @@ pg_restore_attribute_stats(PG_FUNCTION_ARGS)
 										  attarginfo))
 		result = false;
 
-	if (!update_attstats(positional_fcinfo))
+	stats_check_required_arg(positional_fcinfo, attarginfo, ATTRELSCHEMA_ARG);
+	stats_check_required_arg(positional_fcinfo, attarginfo, ATTRELNAME_ARG);
+
+	nspname = TextDatumGetCString(positional_fcinfo->args[ATTRELSCHEMA_ARG].value);
+	relname = TextDatumGetCString(positional_fcinfo->args[ATTRELNAME_ARG].value);
+
+	reloid = stats_acquire_relation_lock(nspname, relname);
+
+	if (!update_attstats(reloid, positional_fcinfo))
 		result = false;
 
 	PG_RETURN_BOOL(result);
@@ -835,48 +820,56 @@ attribute_statistics_update(Relation rel, const char *attname,
 							const char *range_empty_frac,
 							const char *range_bounds_histogram)
 {
-	LOCAL_FCINFO(newfcinfo, NUM_ATTRIBUTE_STATS_ARGS);
+	LOCAL_FCINFO(positional_fcinfo, NUM_ATTRIBUTE_STATS_ARGS);
+	Oid			reloid;
+	char	   *nspname;
+	char	   *relname;
 
-	InitFunctionCallInfoData(*newfcinfo, NULL, NUM_ATTRIBUTE_STATS_ARGS, InvalidOid, NULL, NULL);
+	InitFunctionCallInfoData(*positional_fcinfo, NULL, NUM_ATTRIBUTE_STATS_ARGS, InvalidOid, NULL, NULL);
+
+	nspname = get_namespace_name(RelationGetNamespace(rel));
+	relname = RelationGetRelationName(rel);
+
+	reloid = stats_acquire_relation_lock(nspname, relname);
 
 	/*
 	 * Convert all string inputs to their required datatypes. NULL values are
 	 * left as the default.
 	 */
-	newfcinfo->args[ATTRELSCHEMA_ARG].value = CStringGetTextDatum(get_namespace_name(RelationGetNamespace(rel)));
-	newfcinfo->args[ATTRELSCHEMA_ARG].isnull = false;
-	newfcinfo->args[ATTRELNAME_ARG].value = CStringGetTextDatum(RelationGetRelationName(rel));
-	newfcinfo->args[ATTRELNAME_ARG].isnull = false;
+	positional_fcinfo->args[ATTRELSCHEMA_ARG].value = CStringGetTextDatum(nspname);
+	positional_fcinfo->args[ATTRELSCHEMA_ARG].isnull = false;
+	positional_fcinfo->args[ATTRELNAME_ARG].value = CStringGetTextDatum(relname);
+	positional_fcinfo->args[ATTRELNAME_ARG].isnull = false;
 
-	set_text_arg(&newfcinfo->args[ATTNAME_ARG], attname);
+	set_text_arg(&positional_fcinfo->args[ATTNAME_ARG], attname);
 
 	if (attnum != InvalidAttrNumber)
 	{
-		newfcinfo->args[ATTNUM_ARG].value = Int16GetDatum(attnum);
-		newfcinfo->args[ATTNUM_ARG].isnull = false;
+		positional_fcinfo->args[ATTNUM_ARG].value = Int16GetDatum(attnum);
+		positional_fcinfo->args[ATTNUM_ARG].isnull = false;
 	}
 	else
 	{
-		newfcinfo->args[ATTNUM_ARG].value = (Datum) 0;
-		newfcinfo->args[ATTNUM_ARG].isnull = true;
+		positional_fcinfo->args[ATTNUM_ARG].value = (Datum) 0;
+		positional_fcinfo->args[ATTNUM_ARG].isnull = true;
 	}
 
-	newfcinfo->args[INHERITED_ARG].value = BoolGetDatum(inherited);
-	newfcinfo->args[INHERITED_ARG].isnull = false;
+	positional_fcinfo->args[INHERITED_ARG].value = BoolGetDatum(inherited);
+	positional_fcinfo->args[INHERITED_ARG].isnull = false;
 
-	set_float_arg(&newfcinfo->args[NULL_FRAC_ARG], null_frac);
-	set_int32_arg(&newfcinfo->args[AVG_WIDTH_ARG], avg_width);
-	set_float_arg(&newfcinfo->args[N_DISTINCT_ARG], n_distinct);
-	set_text_arg(&newfcinfo->args[MOST_COMMON_VALS_ARG], most_common_vals);
-	set_floatarr_arg(&newfcinfo->args[MOST_COMMON_FREQS_ARG], most_common_freqs);
-	set_text_arg(&newfcinfo->args[HISTOGRAM_BOUNDS_ARG], histogram_bounds);
-	set_float_arg(&newfcinfo->args[CORRELATION_ARG], correlation);
-	set_text_arg(&newfcinfo->args[MOST_COMMON_ELEMS_ARG], most_common_elems);
-	set_floatarr_arg(&newfcinfo->args[MOST_COMMON_ELEM_FREQS_ARG], most_common_elem_freqs);
-	set_floatarr_arg(&newfcinfo->args[ELEM_COUNT_HISTOGRAM_ARG], elem_count_histogram);
-	set_text_arg(&newfcinfo->args[RANGE_LENGTH_HISTOGRAM_ARG], range_length_histogram);
-	set_float_arg(&newfcinfo->args[RANGE_EMPTY_FRAC_ARG], range_empty_frac);
-	set_text_arg(&newfcinfo->args[RANGE_BOUNDS_HISTOGRAM_ARG], range_bounds_histogram);
+	set_float_arg(&positional_fcinfo->args[NULL_FRAC_ARG], null_frac);
+	set_int32_arg(&positional_fcinfo->args[AVG_WIDTH_ARG], avg_width);
+	set_float_arg(&positional_fcinfo->args[N_DISTINCT_ARG], n_distinct);
+	set_text_arg(&positional_fcinfo->args[MOST_COMMON_VALS_ARG], most_common_vals);
+	set_floatarr_arg(&positional_fcinfo->args[MOST_COMMON_FREQS_ARG], most_common_freqs);
+	set_text_arg(&positional_fcinfo->args[HISTOGRAM_BOUNDS_ARG], histogram_bounds);
+	set_float_arg(&positional_fcinfo->args[CORRELATION_ARG], correlation);
+	set_text_arg(&positional_fcinfo->args[MOST_COMMON_ELEMS_ARG], most_common_elems);
+	set_floatarr_arg(&positional_fcinfo->args[MOST_COMMON_ELEM_FREQS_ARG], most_common_elem_freqs);
+	set_floatarr_arg(&positional_fcinfo->args[ELEM_COUNT_HISTOGRAM_ARG], elem_count_histogram);
+	set_text_arg(&positional_fcinfo->args[RANGE_LENGTH_HISTOGRAM_ARG], range_length_histogram);
+	set_float_arg(&positional_fcinfo->args[RANGE_EMPTY_FRAC_ARG], range_empty_frac);
+	set_text_arg(&positional_fcinfo->args[RANGE_BOUNDS_HISTOGRAM_ARG], range_bounds_histogram);
 
-	return update_attstats(newfcinfo);
+	return update_attstats(reloid, positional_fcinfo);
 }
-- 
2.54.0

