From 90e69b3ce852e2b626b0eaa90299b3329cec0bae Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Fri, 31 Jul 2026 16:44:25 -0400
Subject: [PATCH v3 10/15] Decouple stats_check_* functions from StatsArgInfo
 structure.

Change stats_check_required_arg(), stats_check_arg_array(), and
stats_check_arg_pair() to stop using an array of StatsArgInfo plus an
index to just using a NullableDatum with a char string name provided.

This allows the functions to be useful in situations where there isn't
an array of NullableDatum ordered by a given StatsArgInfo.
---
 src/backend/statistics/attribute_stats.c      | 40 ++++++------
 src/backend/statistics/extended_stats_funcs.c | 20 +++---
 src/backend/statistics/relation_stats.c       |  4 +-
 src/backend/statistics/stat_utils.c           | 61 ++++++++++---------
 src/include/statistics/stat_utils.h           | 15 +++--
 5 files changed, 72 insertions(+), 68 deletions(-)

diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index 4ee14b3ebdf..d053d91e5dc 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -143,8 +143,8 @@ attribute_statistics_update(const NullableDatum *args)
 	bool		inherited;
 	Oid			locked_table = InvalidOid;
 
-	stats_check_required_arg(args, attarginfo, ATTARG_ATTRELSCHEMA);
-	stats_check_required_arg(args, attarginfo, ATTARG_ATTRELNAME);
+	stats_check_required_arg(&args[ATTARG_ATTRELSCHEMA], attarginfo[ATTARG_ATTRELSCHEMA].argname);
+	stats_check_required_arg(&args[ATTARG_ATTRELNAME], attarginfo[ATTARG_ATTRELNAME].argname);
 
 	nspname = TextDatumGetCString(args[ATTARG_ATTRELSCHEMA].value);
 	relname = TextDatumGetCString(args[ATTARG_ATTRELNAME].value);
@@ -203,7 +203,7 @@ attribute_statistics_update(const NullableDatum *args)
 				 errmsg("cannot modify statistics on system column \"%s\"",
 						attname)));
 
-	stats_check_required_arg(args, attarginfo, ATTARG_INHERITED);
+	stats_check_required_arg(&args[ATTARG_INHERITED], attarginfo[ATTARG_INHERITED].argname);
 	inherited = DatumGetBool(args[ATTARG_INHERITED].value);
 
 	return attribute_statistics_update_internal(reloid, attname, attnum,
@@ -255,41 +255,45 @@ attribute_statistics_update_internal(Oid reloid,
 	 * and set the corresponding argument to NULL in fcinfo.
 	 */
 
-	if (!stats_check_arg_array(args, attarginfo, ATTARG_MOST_COMMON_FREQS))
+	if (!stats_check_arg_array(&args[ATTARG_MOST_COMMON_FREQS], attarginfo[ATTARG_MOST_COMMON_FREQS].argname))
 	{
 		do_mcv = false;
 		result = false;
 	}
 
-	if (!stats_check_arg_array(args, attarginfo, ATTARG_MOST_COMMON_ELEM_FREQS))
+	if (!stats_check_arg_array(&args[ATTARG_MOST_COMMON_ELEM_FREQS], attarginfo[ATTARG_MOST_COMMON_ELEM_FREQS].argname))
 	{
 		do_mcelem = false;
 		result = false;
 	}
-	if (!stats_check_arg_array(args, attarginfo, ATTARG_ELEM_COUNT_HISTOGRAM))
+	if (!stats_check_arg_array(&args[ATTARG_ELEM_COUNT_HISTOGRAM], attarginfo[ATTARG_ELEM_COUNT_HISTOGRAM].argname))
 	{
 		do_dechist = false;
 		result = false;
 	}
 
-	if (!stats_check_arg_pair(args, attarginfo,
-							  ATTARG_MOST_COMMON_VALS, ATTARG_MOST_COMMON_FREQS))
+	if (!stats_check_arg_pair(&args[ATTARG_MOST_COMMON_VALS],
+							  &args[ATTARG_MOST_COMMON_FREQS],
+							  attarginfo[ATTARG_MOST_COMMON_VALS].argname,
+							  attarginfo[ATTARG_MOST_COMMON_FREQS].argname))
 	{
 		do_mcv = false;
 		result = false;
 	}
 
-	if (!stats_check_arg_pair(args, attarginfo,
-							  ATTARG_MOST_COMMON_ELEMS,
-							  ATTARG_MOST_COMMON_ELEM_FREQS))
+	if (!stats_check_arg_pair(&args[ATTARG_MOST_COMMON_ELEMS],
+							  &args[ATTARG_MOST_COMMON_ELEM_FREQS],
+							  attarginfo[ATTARG_MOST_COMMON_ELEMS].argname,
+							  attarginfo[ATTARG_MOST_COMMON_ELEM_FREQS].argname))
 	{
 		do_mcelem = false;
 		result = false;
 	}
 
-	if (!stats_check_arg_pair(args, attarginfo,
-							  ATTARG_RANGE_LENGTH_HISTOGRAM,
-							  ATTARG_RANGE_EMPTY_FRAC))
+	if (!stats_check_arg_pair(&args[ATTARG_RANGE_LENGTH_HISTOGRAM],
+							  &args[ATTARG_RANGE_EMPTY_FRAC],
+							  attarginfo[ATTARG_RANGE_LENGTH_HISTOGRAM].argname,
+							  attarginfo[ATTARG_RANGE_EMPTY_FRAC].argname))
 	{
 		do_range_length_histogram = false;
 		result = false;
@@ -625,10 +629,10 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
 	bool		inherited;
 	Oid			locked_table = InvalidOid;
 
-	stats_check_required_arg(fcinfo->args, cleararginfo, C_ATTARG_ATTRELSCHEMA);
-	stats_check_required_arg(fcinfo->args, cleararginfo, C_ATTARG_ATTRELNAME);
-	stats_check_required_arg(fcinfo->args, cleararginfo, C_ATTARG_ATTNAME);
-	stats_check_required_arg(fcinfo->args, cleararginfo, C_ATTARG_INHERITED);
+	stats_check_required_arg(&fcinfo->args[C_ATTARG_ATTRELSCHEMA], cleararginfo[C_ATTARG_ATTRELSCHEMA].argname);
+	stats_check_required_arg(&fcinfo->args[C_ATTARG_ATTRELNAME], cleararginfo[C_ATTARG_ATTRELNAME].argname);
+	stats_check_required_arg(&fcinfo->args[C_ATTARG_ATTNAME], cleararginfo[C_ATTARG_ATTNAME].argname);
+	stats_check_required_arg(&fcinfo->args[C_ATTARG_INHERITED], cleararginfo[C_ATTARG_INHERITED].argname);
 
 	nspname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTARG_ATTRELSCHEMA));
 	relname = TextDatumGetCString(PG_GETARG_DATUM(C_ATTARG_ATTRELNAME));
diff --git a/src/backend/statistics/extended_stats_funcs.c b/src/backend/statistics/extended_stats_funcs.c
index 1b730b26c44..0c84160a824 100644
--- a/src/backend/statistics/extended_stats_funcs.c
+++ b/src/backend/statistics/extended_stats_funcs.c
@@ -375,17 +375,17 @@ extended_statistics_update(const NullableDatum *args)
 	}
 
 	/* relation arguments */
-	stats_check_required_arg(args, extarginfo, EXTARG_RELSCHEMA);
+	stats_check_required_arg(&args[EXTARG_RELSCHEMA], extarginfo[EXTARG_RELSCHEMA].argname);
 	relnspname = TextDatumGetCString(args[EXTARG_RELSCHEMA].value);
-	stats_check_required_arg(args, extarginfo, EXTARG_RELNAME);
+	stats_check_required_arg(&args[EXTARG_RELNAME], extarginfo[EXTARG_RELNAME].argname);
 	relname = TextDatumGetCString(args[EXTARG_RELNAME].value);
 
 	/* extended statistics arguments */
-	stats_check_required_arg(args, extarginfo, EXTARG_STATSCHEMA);
+	stats_check_required_arg(&args[EXTARG_STATSCHEMA], extarginfo[EXTARG_STATSCHEMA].argname);
 	nspname = TextDatumGetCString(args[EXTARG_STATSCHEMA].value);
-	stats_check_required_arg(args, extarginfo, EXTARG_STATNAME);
+	stats_check_required_arg(&args[EXTARG_STATNAME], extarginfo[EXTARG_STATNAME].argname);
 	stxname = TextDatumGetCString(args[EXTARG_STATNAME].value);
-	stats_check_required_arg(args, extarginfo, EXTARG_INHERITED);
+	stats_check_required_arg(&args[EXTARG_INHERITED], extarginfo[EXTARG_INHERITED].argname);
 	inherited = DatumGetBool(args[EXTARG_INHERITED].value);
 
 	/*
@@ -1757,17 +1757,17 @@ pg_clear_extended_stats(PG_FUNCTION_ARGS)
 	Oid			locked_table = InvalidOid;
 
 	/* relation arguments */
-	stats_check_required_arg(fcinfo->args, extarginfo, EXTARG_RELSCHEMA);
+	stats_check_required_arg(&fcinfo->args[EXTARG_RELSCHEMA], extarginfo[EXTARG_RELSCHEMA].argname);
 	relnspname = TextDatumGetCString(PG_GETARG_DATUM(EXTARG_RELSCHEMA));
-	stats_check_required_arg(fcinfo->args, extarginfo, EXTARG_RELNAME);
+	stats_check_required_arg(&fcinfo->args[EXTARG_RELNAME], extarginfo[EXTARG_RELNAME].argname);
 	relname = TextDatumGetCString(PG_GETARG_DATUM(EXTARG_RELNAME));
 
 	/* extended statistics arguments */
-	stats_check_required_arg(fcinfo->args, extarginfo, EXTARG_STATSCHEMA);
+	stats_check_required_arg(&fcinfo->args[EXTARG_STATSCHEMA], extarginfo[EXTARG_STATSCHEMA].argname);
 	nspname = TextDatumGetCString(PG_GETARG_DATUM(EXTARG_STATSCHEMA));
-	stats_check_required_arg(fcinfo->args, extarginfo, EXTARG_STATNAME);
+	stats_check_required_arg(&fcinfo->args[EXTARG_STATNAME], extarginfo[EXTARG_STATNAME].argname);
 	stxname = TextDatumGetCString(PG_GETARG_DATUM(EXTARG_STATNAME));
-	stats_check_required_arg(fcinfo->args, extarginfo, EXTARG_INHERITED);
+	stats_check_required_arg(&fcinfo->args[EXTARG_INHERITED], extarginfo[EXTARG_INHERITED].argname);
 	inherited = PG_GETARG_BOOL(EXTARG_INHERITED);
 
 	if (RecoveryInProgress())
diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c
index eaf7a1e326b..2e62cf5b9e3 100644
--- a/src/backend/statistics/relation_stats.c
+++ b/src/backend/statistics/relation_stats.c
@@ -76,8 +76,8 @@ relation_statistics_update(const NullableDatum *args)
 	Oid			reloid;
 	Oid			locked_table = InvalidOid;
 
-	stats_check_required_arg(args, relarginfo, RELARG_SCHEMA);
-	stats_check_required_arg(args, relarginfo, RELARG_RELNAME);
+	stats_check_required_arg(&args[RELARG_SCHEMA], relarginfo[RELARG_SCHEMA].argname);
+	stats_check_required_arg(&args[RELARG_RELNAME], relarginfo[RELARG_RELNAME].argname);
 
 	nspname = TextDatumGetCString(args[RELARG_SCHEMA].value);
 	relname = TextDatumGetCString(args[RELARG_RELNAME].value);
diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c
index 29655d55339..f4d238c5ce0 100644
--- a/src/backend/statistics/stat_utils.c
+++ b/src/backend/statistics/stat_utils.c
@@ -51,15 +51,15 @@ static Node *statatt_get_index_expr(Relation rel, int attnum);
  * Ensure that a given argument is not null.
  */
 void
-stats_check_required_arg(const NullableDatum *args,
-						 struct StatsArgInfo *arginfo,
-						 int argnum)
+stats_check_required_arg(const NullableDatum *arg,
+						 const char *argname)
 {
-	if (args[argnum].isnull)
+	Assert(arg);
+
+	if (arg->isnull)
 		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("argument \"%s\" must not be null",
-						arginfo[argnum].argname)));
+				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("argument \"%s\" must not be null", argname));
 }
 
 /*
@@ -70,32 +70,33 @@ stats_check_required_arg(const NullableDatum *args,
  * true.
  */
 bool
-stats_check_arg_array(const NullableDatum *args,
-					  struct StatsArgInfo *arginfo,
-					  int argnum)
+stats_check_arg_array(const NullableDatum *arg,
+					  const char *argname)
 {
 	ArrayType  *arr;
 
-	if (args[argnum].isnull)
+	Assert(arg);
+
+	if (arg->isnull)
 		return true;
 
-	arr = DatumGetArrayTypeP(args[argnum].value);
+	arr = DatumGetArrayTypeP(arg->value);
 
 	if (ARR_NDIM(arr) != 1)
 	{
 		ereport(WARNING,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("argument \"%s\" must not be a multidimensional array",
-						arginfo[argnum].argname)));
+				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("argument \"%s\" must not be a multidimensional array",
+					   argname));
 		return false;
 	}
 
 	if (array_contains_nulls(arr))
 	{
 		ereport(WARNING,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("argument \"%s\" array must not contain null values",
-						arginfo[argnum].argname)));
+				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("argument \"%s\" array must not contain null values",
+					   argname));
 		return false;
 	}
 
@@ -111,23 +112,23 @@ stats_check_arg_array(const NullableDatum *args,
  * true.
  */
 bool
-stats_check_arg_pair(const NullableDatum *args,
-					 struct StatsArgInfo *arginfo,
-					 int argnum1, int argnum2)
+stats_check_arg_pair(const NullableDatum *arg1,
+					 const NullableDatum *arg2,
+					 const char *argname1,
+					 const char *argname2)
 {
-	if (args[argnum1].isnull && args[argnum2].isnull)
-		return true;
+	Assert(arg1);
+	Assert(arg2);
 
-	if (args[argnum1].isnull || args[argnum2].isnull)
+	if (arg1->isnull != arg2->isnull)
 	{
-		int			nullarg = args[argnum1].isnull ? argnum1 : argnum2;
-		int			otherarg = args[argnum1].isnull ? argnum2 : argnum1;
+		const char *nullargname = arg1->isnull ? argname1 : argname2;
+		const char *otherargname = arg1->isnull ? argname2 : argname1;
 
 		ereport(WARNING,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("argument \"%s\" must be specified when argument \"%s\" is specified",
-						arginfo[nullarg].argname,
-						arginfo[otherarg].argname)));
+				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("argument \"%s\" must be specified when argument \"%s\" is specified",
+					   nullargname, otherargname));
 
 		return false;
 	}
diff --git a/src/include/statistics/stat_utils.h b/src/include/statistics/stat_utils.h
index 39027a4ab03..4bdf7275425 100644
--- a/src/include/statistics/stat_utils.h
+++ b/src/include/statistics/stat_utils.h
@@ -26,14 +26,13 @@ struct StatsArgInfo
 	Oid			argtype;
 };
 
-extern void stats_check_required_arg(const NullableDatum *args,
-									 struct StatsArgInfo *arginfo,
-									 int argnum);
-extern bool stats_check_arg_array(const NullableDatum *args,
-								  struct StatsArgInfo *arginfo, int argnum);
-extern bool stats_check_arg_pair(const NullableDatum *args,
-								 struct StatsArgInfo *arginfo,
-								 int argnum1, int argnum2);
+extern void stats_check_required_arg(const NullableDatum *arg,
+									 const char *argname);
+extern bool stats_check_arg_array(const NullableDatum *arg,
+								  const char *argname);
+extern bool stats_check_arg_pair(const NullableDatum *arg1,
+								 const NullableDatum *arg2,
+								 const char *argname1, const char *argname2);
 
 extern void RangeVarCallbackForStats(const RangeVar *relation,
 									 Oid relId, Oid oldRelId, void *arg);
-- 
2.50.1 (Apple Git-155)

