From 5e0a3c7cf741333bf94065616c60074170a84033 Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Tue, 4 Nov 2025 23:50:01 -0500
Subject: [PATCH v8 5/7] Expose attribute statistics functions for use in
 extended_stats.

Many of the operations of attribute stats have analogous operations in
extended stats.

* get_attr_stat_type() renamed to statatt_get_type()
* init_empty_stats_tuple() renamed to statatt_init_empty_tuple()
* text_to_stavalues()
* get_elem_stat_type() renamed to statatt_get_elem_type()

Also, add comments explaining the function argument index enums, and the
arrays that are indexed by those enums.
---
 src/include/statistics/statistics.h      |  17 +++
 src/backend/statistics/attribute_stats.c | 126 +++++++++++------------
 2 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/src/include/statistics/statistics.h b/src/include/statistics/statistics.h
index 7dd0f9755454..0df66b352a10 100644
--- a/src/include/statistics/statistics.h
+++ b/src/include/statistics/statistics.h
@@ -127,4 +127,21 @@ extern StatisticExtInfo *choose_best_statistics(List *stats, char requiredkind,
 												int nclauses);
 extern HeapTuple statext_expressions_load(Oid stxoid, bool inh, int idx);
 
+extern void statatt_get_type(Oid reloid, AttrNumber attnum,
+							 Oid *atttypid, int32 *atttypmod,
+							 char *atttyptype, Oid *atttypcoll,
+							 Oid *eq_opr, Oid *lt_opr);
+extern void statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited,
+									 Datum *values, bool *nulls, bool *replaces);
+
+extern void statatt_set_slot(Datum *values, bool *nulls, bool *replaces,
+							 int16 stakind, Oid staop, Oid stacoll,
+							 Datum stanumbers, bool stanumbers_isnull,
+							 Datum stavalues, bool stavalues_isnull);
+
+extern Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d,
+							   Oid typid, int32 typmod, bool *ok);
+extern bool statatt_get_elem_type(Oid atttypid, char atttyptype,
+								  Oid *elemtypid, Oid *elem_eq_opr);
+
 #endif							/* STATISTICS_H */
diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index ef4d768feab7..d0c67a4128e0 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -64,6 +64,10 @@ enum attribute_stats_argnum
 	NUM_ATTRIBUTE_STATS_ARGS
 };
 
+/*
+ * The argument names and typoids of the arguments for
+ * attribute_statistics_update.
+ */
 static struct StatsArgInfo attarginfo[] =
 {
 	[ATTRELSCHEMA_ARG] = {"schemaname", TEXTOID},
@@ -101,6 +105,10 @@ enum clear_attribute_stats_argnum
 	C_NUM_ATTRIBUTE_STATS_ARGS
 };
 
+/*
+ * The argument names and typoids of the arguments for
+ * pg_clear_attribute_stats.
+ */
 static struct StatsArgInfo cleararginfo[] =
 {
 	[C_ATTRELSCHEMA_ARG] = {"relation", TEXTOID},
@@ -112,23 +120,9 @@ static struct StatsArgInfo cleararginfo[] =
 
 static bool attribute_statistics_update(FunctionCallInfo fcinfo);
 static Node *get_attr_expr(Relation rel, int attnum);
-static void get_attr_stat_type(Oid reloid, AttrNumber attnum,
-							   Oid *atttypid, int32 *atttypmod,
-							   char *atttyptype, Oid *atttypcoll,
-							   Oid *eq_opr, Oid *lt_opr);
-static bool get_elem_stat_type(Oid atttypid, char atttyptype,
-							   Oid *elemtypid, Oid *elem_eq_opr);
-static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d,
-							   Oid typid, int32 typmod, bool *ok);
-static void set_stats_slot(Datum *values, bool *nulls, bool *replaces,
-						   int16 stakind, Oid staop, Oid stacoll,
-						   Datum stanumbers, bool stanumbers_isnull,
-						   Datum stavalues, bool stavalues_isnull);
 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);
-static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
-								   Datum *values, bool *nulls, bool *replaces);
 
 /*
  * Insert or Update Attribute Statistics
@@ -298,16 +292,16 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 	}
 
 	/* derive information from attribute */
-	get_attr_stat_type(reloid, attnum,
-					   &atttypid, &atttypmod,
-					   &atttyptype, &atttypcoll,
-					   &eq_opr, &lt_opr);
+	statatt_get_type(reloid, attnum,
+					 &atttypid, &atttypmod,
+					 &atttyptype, &atttypcoll,
+					 &eq_opr, &lt_opr);
 
 	/* if needed, derive element type */
 	if (do_mcelem || do_dechist)
 	{
-		if (!get_elem_stat_type(atttypid, atttyptype,
-								&elemtypid, &elem_eq_opr))
+		if (!statatt_get_elem_type(atttypid, atttyptype,
+								   &elemtypid, &elem_eq_opr))
 		{
 			ereport(WARNING,
 					(errmsg("could not determine element type of column \"%s\"", attname),
@@ -361,7 +355,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 	if (HeapTupleIsValid(statup))
 		heap_deform_tuple(statup, RelationGetDescr(starel), values, nulls);
 	else
-		init_empty_stats_tuple(reloid, attnum, inherited, values, nulls,
+		statatt_init_empty_tuple(reloid, attnum, inherited, values, nulls,
 							   replaces);
 
 	/* if specified, set to argument values */
@@ -394,10 +388,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 		if (converted)
 		{
-			set_stats_slot(values, nulls, replaces,
-						   STATISTIC_KIND_MCV,
-						   eq_opr, atttypcoll,
-						   stanumbers, false, stavalues, false);
+			statatt_set_slot(values, nulls, replaces,
+							 STATISTIC_KIND_MCV,
+							 eq_opr, atttypcoll,
+							 stanumbers, false, stavalues, false);
 		}
 		else
 			result = false;
@@ -417,10 +411,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 		if (converted)
 		{
-			set_stats_slot(values, nulls, replaces,
-						   STATISTIC_KIND_HISTOGRAM,
-						   lt_opr, atttypcoll,
-						   0, true, stavalues, false);
+			statatt_set_slot(values, nulls, replaces,
+							 STATISTIC_KIND_HISTOGRAM,
+							 lt_opr, atttypcoll,
+							 0, true, stavalues, false);
 		}
 		else
 			result = false;
@@ -433,10 +427,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 		ArrayType  *arry = construct_array_builtin(elems, 1, FLOAT4OID);
 		Datum		stanumbers = PointerGetDatum(arry);
 
-		set_stats_slot(values, nulls, replaces,
-					   STATISTIC_KIND_CORRELATION,
-					   lt_opr, atttypcoll,
-					   stanumbers, false, 0, true);
+		statatt_set_slot(values, nulls, replaces,
+						 STATISTIC_KIND_CORRELATION,
+						 lt_opr, atttypcoll,
+						 stanumbers, false, 0, true);
 	}
 
 	/* STATISTIC_KIND_MCELEM */
@@ -454,10 +448,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 		if (converted)
 		{
-			set_stats_slot(values, nulls, replaces,
-						   STATISTIC_KIND_MCELEM,
-						   elem_eq_opr, atttypcoll,
-						   stanumbers, false, stavalues, false);
+			statatt_set_slot(values, nulls, replaces,
+							 STATISTIC_KIND_MCELEM,
+							 elem_eq_opr, atttypcoll,
+							 stanumbers, false, stavalues, false);
 		}
 		else
 			result = false;
@@ -468,10 +462,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 	{
 		Datum		stanumbers = PG_GETARG_DATUM(ELEM_COUNT_HISTOGRAM_ARG);
 
-		set_stats_slot(values, nulls, replaces,
-					   STATISTIC_KIND_DECHIST,
-					   elem_eq_opr, atttypcoll,
-					   stanumbers, false, 0, true);
+		statatt_set_slot(values, nulls, replaces,
+						 STATISTIC_KIND_DECHIST,
+						 elem_eq_opr, atttypcoll,
+						 stanumbers, false, 0, true);
 	}
 
 	/*
@@ -494,10 +488,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 		if (converted)
 		{
-			set_stats_slot(values, nulls, replaces,
-						   STATISTIC_KIND_BOUNDS_HISTOGRAM,
-						   InvalidOid, InvalidOid,
-						   0, true, stavalues, false);
+			statatt_set_slot(values, nulls, replaces,
+							 STATISTIC_KIND_BOUNDS_HISTOGRAM,
+							 InvalidOid, InvalidOid,
+							 0, true, stavalues, false);
 		}
 		else
 			result = false;
@@ -521,10 +515,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 		if (converted)
 		{
-			set_stats_slot(values, nulls, replaces,
-						   STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM,
-						   Float8LessOperator, InvalidOid,
-						   stanumbers, false, stavalues, false);
+			statatt_set_slot(values, nulls, replaces,
+							 STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM,
+							 Float8LessOperator, InvalidOid,
+							 stanumbers, false, stavalues, false);
 		}
 		else
 			result = false;
@@ -584,11 +578,11 @@ get_attr_expr(Relation rel, int attnum)
 /*
  * Derive type information from the attribute.
  */
-static void
-get_attr_stat_type(Oid reloid, AttrNumber attnum,
-				   Oid *atttypid, int32 *atttypmod,
-				   char *atttyptype, Oid *atttypcoll,
-				   Oid *eq_opr, Oid *lt_opr)
+void
+statatt_get_type(Oid reloid, AttrNumber attnum,
+				 Oid *atttypid, int32 *atttypmod,
+				 char *atttyptype, Oid *atttypcoll,
+				 Oid *eq_opr, Oid *lt_opr)
 {
 	Relation	rel = relation_open(reloid, AccessShareLock);
 	Form_pg_attribute attr;
@@ -666,9 +660,9 @@ get_attr_stat_type(Oid reloid, AttrNumber attnum,
 /*
  * Derive element type information from the attribute type.
  */
-static bool
-get_elem_stat_type(Oid atttypid, char atttyptype,
-				   Oid *elemtypid, Oid *elem_eq_opr)
+bool
+statatt_get_elem_type(Oid atttypid, char atttyptype,
+					  Oid *elemtypid, Oid *elem_eq_opr)
 {
 	TypeCacheEntry *elemtypcache;
 
@@ -706,7 +700,7 @@ get_elem_stat_type(Oid atttypid, char atttyptype,
  * to false. If the resulting array contains NULLs, raise a WARNING and set ok
  * to false. Otherwise, set ok to true.
  */
-static Datum
+Datum
 text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
 				  int32 typmod, bool *ok)
 {
@@ -759,11 +753,11 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
  * Find and update the slot with the given stakind, or use the first empty
  * slot.
  */
-static void
-set_stats_slot(Datum *values, bool *nulls, bool *replaces,
-			   int16 stakind, Oid staop, Oid stacoll,
-			   Datum stanumbers, bool stanumbers_isnull,
-			   Datum stavalues, bool stavalues_isnull)
+void
+statatt_set_slot(Datum *values, bool *nulls, bool *replaces,
+				 int16 stakind, Oid staop, Oid stacoll,
+				 Datum stanumbers, bool stanumbers_isnull,
+				 Datum stavalues, bool stavalues_isnull)
 {
 	int			slotidx;
 	int			first_empty = -1;
@@ -883,9 +877,9 @@ delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit)
 /*
  * Initialize values and nulls for a new stats tuple.
  */
-static void
-init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
-					   Datum *values, bool *nulls, bool *replaces)
+void
+statatt_init_empty_tuple(Oid reloid, int16 attnum, bool inherited,
+						 Datum *values, bool *nulls, bool *replaces)
 {
 	memset(nulls, true, sizeof(bool) * Natts_pg_statistic);
 	memset(replaces, true, sizeof(bool) * Natts_pg_statistic);
-- 
2.51.0

