From 8b1f72fa74b3b6cb348a3a08ac7c67cb8e2e4c5f Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Tue, 11 Nov 2025 13:27:13 +0900
Subject: [PATCH v10 1/9] Make pg_ndinstinct a proper adt.

Move the in/out/send/recv functions for pg_ndistinct to pg_ndistinct.c,
which allows mvdistinct.c to focus on the transformation from sample
data to the internal MVDistinct structure.
---
 src/backend/statistics/mvdistinct.c  |  85 ----------------------
 src/backend/utils/adt/Makefile       |   1 +
 src/backend/utils/adt/meson.build    |   1 +
 src/backend/utils/adt/pg_ndistinct.c | 102 +++++++++++++++++++++++++++
 4 files changed, 104 insertions(+), 85 deletions(-)
 create mode 100644 src/backend/utils/adt/pg_ndistinct.c

diff --git a/src/backend/statistics/mvdistinct.c b/src/backend/statistics/mvdistinct.c
index 7e7a63405c8b..fe452f53ae4b 100644
--- a/src/backend/statistics/mvdistinct.c
+++ b/src/backend/statistics/mvdistinct.c
@@ -27,10 +27,7 @@
 
 #include "catalog/pg_statistic_ext.h"
 #include "catalog/pg_statistic_ext_data.h"
-#include "lib/stringinfo.h"
 #include "statistics/extended_stats_internal.h"
-#include "statistics/statistics.h"
-#include "utils/fmgrprotos.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 #include "varatt.h"
@@ -328,88 +325,6 @@ statext_ndistinct_deserialize(bytea *data)
 	return ndistinct;
 }
 
-/*
- * pg_ndistinct_in
- *		input routine for type pg_ndistinct
- *
- * pg_ndistinct is real enough to be a table column, but it has no
- * operations of its own, and disallows input (just like pg_node_tree).
- */
-Datum
-pg_ndistinct_in(PG_FUNCTION_ARGS)
-{
-	ereport(ERROR,
-			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			 errmsg("cannot accept a value of type %s", "pg_ndistinct")));
-
-	PG_RETURN_VOID();			/* keep compiler quiet */
-}
-
-/*
- * pg_ndistinct
- *		output routine for type pg_ndistinct
- *
- * Produces a human-readable representation of the value.
- */
-Datum
-pg_ndistinct_out(PG_FUNCTION_ARGS)
-{
-	bytea	   *data = PG_GETARG_BYTEA_PP(0);
-	MVNDistinct *ndist = statext_ndistinct_deserialize(data);
-	int			i;
-	StringInfoData str;
-
-	initStringInfo(&str);
-	appendStringInfoChar(&str, '{');
-
-	for (i = 0; i < ndist->nitems; i++)
-	{
-		int			j;
-		MVNDistinctItem item = ndist->items[i];
-
-		if (i > 0)
-			appendStringInfoString(&str, ", ");
-
-		for (j = 0; j < item.nattributes; j++)
-		{
-			AttrNumber	attnum = item.attributes[j];
-
-			appendStringInfo(&str, "%s%d", (j == 0) ? "\"" : ", ", attnum);
-		}
-		appendStringInfo(&str, "\": %d", (int) item.ndistinct);
-	}
-
-	appendStringInfoChar(&str, '}');
-
-	PG_RETURN_CSTRING(str.data);
-}
-
-/*
- * pg_ndistinct_recv
- *		binary input routine for type pg_ndistinct
- */
-Datum
-pg_ndistinct_recv(PG_FUNCTION_ARGS)
-{
-	ereport(ERROR,
-			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			 errmsg("cannot accept a value of type %s", "pg_ndistinct")));
-
-	PG_RETURN_VOID();			/* keep compiler quiet */
-}
-
-/*
- * pg_ndistinct_send
- *		binary output routine for type pg_ndistinct
- *
- * n-distinct is serialized into a bytea value, so let's send that.
- */
-Datum
-pg_ndistinct_send(PG_FUNCTION_ARGS)
-{
-	return byteasend(fcinfo);
-}
-
 /*
  * ndistinct_for_combination
  *		Estimates number of distinct values in a combination of columns.
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index cc68ac545a5f..70ff8e455169 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -85,6 +85,7 @@ OBJS = \
 	pg_locale_icu.o \
 	pg_locale_libc.o \
 	pg_lsn.o \
+	pg_ndistinct.o \
 	pg_upgrade_support.o \
 	pgstatfuncs.o \
 	pseudorandomfuncs.o \
diff --git a/src/backend/utils/adt/meson.build b/src/backend/utils/adt/meson.build
index 12fa0c209127..b6b642c77a04 100644
--- a/src/backend/utils/adt/meson.build
+++ b/src/backend/utils/adt/meson.build
@@ -81,6 +81,7 @@ backend_sources += files(
   'pg_locale_icu.c',
   'pg_locale_libc.c',
   'pg_lsn.c',
+  'pg_ndistinct.c',
   'pg_upgrade_support.c',
   'pgstatfuncs.c',
   'pseudorandomfuncs.c',
diff --git a/src/backend/utils/adt/pg_ndistinct.c b/src/backend/utils/adt/pg_ndistinct.c
new file mode 100644
index 000000000000..5ce655bce755
--- /dev/null
+++ b/src/backend/utils/adt/pg_ndistinct.c
@@ -0,0 +1,102 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_ndistinct.c
+ *		pg_ndistinct data type support.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/adt/pg_ndistinct.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "lib/stringinfo.h"
+#include "statistics/extended_stats_internal.h"
+#include "utils/fmgrprotos.h"
+
+
+/*
+ * pg_ndistinct_in
+ *		input routine for type pg_ndistinct
+ *
+ * pg_ndistinct is real enough to be a table column, but it has no
+ * operations of its own, and disallows input (just like pg_node_tree).
+ */
+Datum
+pg_ndistinct_in(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type %s", "pg_ndistinct")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * pg_ndistinct
+ *		output routine for type pg_ndistinct
+ *
+ * Produces a human-readable representation of the value.
+ */
+Datum
+pg_ndistinct_out(PG_FUNCTION_ARGS)
+{
+	bytea	   *data = PG_GETARG_BYTEA_PP(0);
+	MVNDistinct *ndist = statext_ndistinct_deserialize(data);
+	int			i;
+	StringInfoData str;
+
+	initStringInfo(&str);
+	appendStringInfoChar(&str, '{');
+
+	for (i = 0; i < ndist->nitems; i++)
+	{
+		int			j;
+		MVNDistinctItem item = ndist->items[i];
+
+		if (i > 0)
+			appendStringInfoString(&str, ", ");
+
+		for (j = 0; j < item.nattributes; j++)
+		{
+			AttrNumber	attnum = item.attributes[j];
+
+			appendStringInfo(&str, "%s%d", (j == 0) ? "\"" : ", ", attnum);
+		}
+		appendStringInfo(&str, "\": %d", (int) item.ndistinct);
+	}
+
+	appendStringInfoChar(&str, '}');
+
+	PG_RETURN_CSTRING(str.data);
+}
+
+/*
+ * pg_ndistinct_recv
+ *		binary input routine for type pg_ndistinct
+ */
+Datum
+pg_ndistinct_recv(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type %s", "pg_ndistinct")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * pg_ndistinct_send
+ *		binary output routine for type pg_ndistinct
+ *
+ * n-distinct is serialized into a bytea value, so let's send that.
+ */
+Datum
+pg_ndistinct_send(PG_FUNCTION_ARGS)
+{
+	return byteasend(fcinfo);
+}
-- 
2.51.0

