v6-0004-Avoid-getAttributeStats-call-for-indexes-without-.patch

text/x-patch

Filename: v6-0004-Avoid-getAttributeStats-call-for-indexes-without-.patch
Type: text/x-patch
Part: 2
Message: Re: Statistics Import and Export

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v6-0004
Subject: Avoid getAttributeStats() call for indexes without an expression column.
File+
src/bin/pg_dump/pg_dump.c 122 107
From 5ea8a35a1d6db14046bb2fb76dfcdddb1bcf9479 Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Wed, 5 Mar 2025 22:40:40 -0500
Subject: [PATCH v6 4/4] Avoid getAttributeStats() call for indexes without an
 expression column.

---
 src/bin/pg_dump/pg_dump.c | 229 ++++++++++++++++++++------------------
 1 file changed, 122 insertions(+), 107 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 6cf2c7d1fe4..0cc2a65caa3 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -10487,7 +10487,6 @@ static void
 dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
 {
 	const DumpableObject *dobj = &rsinfo->dobj;
-	PGresult   *res;
 	PQExpBuffer query;
 	PQExpBuffer out;
 	DumpId	   *deps = NULL;
@@ -10508,11 +10507,22 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
 	int			i_range_length_histogram;
 	int			i_range_empty_frac;
 	int			i_range_bounds_histogram;
+	bool		can_have_attrstats = true;
 
 	/* nothing to do if we are not dumping statistics */
 	if (!fout->dopt->dumpStatistics)
 		return;
 
+	/*
+	 * Indexes can only have statistics for expression columns.
+	 */
+	if ((rsinfo->relkind == RELKIND_INDEX) ||
+		(rsinfo->relkind == RELKIND_PARTITIONED_INDEX))
+	{
+		if (rsinfo->nindAttNames == 0)
+			can_have_attrstats = false;
+	}
+
 	/* dependent on the relation definition, if doing schema */
 	if (fout->dopt->dumpSchema)
 	{
@@ -10573,127 +10583,132 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
 	appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer\n);\n",
 					  rsinfo->relallvisible);
 
-	/* fetch attribute stats */
-	appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
-	appendStringLiteralAH(query, dobj->namespace->dobj.name, fout);
-	appendPQExpBufferStr(query, ", ");
-	appendStringLiteralAH(query, dobj->name, fout);
-	appendPQExpBufferStr(query, ");");
-
-	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
-
-	i_attname = PQfnumber(res, "attname");
-	i_inherited = PQfnumber(res, "inherited");
-	i_null_frac = PQfnumber(res, "null_frac");
-	i_avg_width = PQfnumber(res, "avg_width");
-	i_n_distinct = PQfnumber(res, "n_distinct");
-	i_most_common_vals = PQfnumber(res, "most_common_vals");
-	i_most_common_freqs = PQfnumber(res, "most_common_freqs");
-	i_histogram_bounds = PQfnumber(res, "histogram_bounds");
-	i_correlation = PQfnumber(res, "correlation");
-	i_most_common_elems = PQfnumber(res, "most_common_elems");
-	i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
-	i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
-	i_range_length_histogram = PQfnumber(res, "range_length_histogram");
-	i_range_empty_frac = PQfnumber(res, "range_empty_frac");
-	i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
-
-	/* restore attribute stats */
-	for (int rownum = 0; rownum < PQntuples(res); rownum++)
+	if (can_have_attrstats)
 	{
-		const char *attname;
+		PGresult   *res;
 
-		appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
-		appendPQExpBuffer(out, "\t'version', '%u'::integer,\n",
-						  fout->remoteVersion);
-		appendPQExpBufferStr(out, "\t'schemaname', ");
-		appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
-		appendPQExpBufferStr(out, ",\n\t'relname', ");
-		appendStringLiteralAH(out, rsinfo->dobj.name, fout);
+		/* fetch attribute stats */
+		appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
+		appendStringLiteralAH(query, dobj->namespace->dobj.name, fout);
+		appendPQExpBufferStr(query, ", ");
+		appendStringLiteralAH(query, dobj->name, fout);
+		appendPQExpBufferStr(query, ");");
 
-		if (PQgetisnull(res, rownum, i_attname))
-			pg_fatal("attname cannot be NULL");
-		attname = PQgetvalue(res, rownum, i_attname);
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
-		/*
-		 * Indexes look up attname in indAttNames to derive attnum, all others
-		 * use attname directly.  We must specify attnum for indexes, since
-		 * their attnames are not necessarily stable across dump/reload.
-		 */
-		if (rsinfo->nindAttNames == 0)
+		i_attname = PQfnumber(res, "attname");
+		i_inherited = PQfnumber(res, "inherited");
+		i_null_frac = PQfnumber(res, "null_frac");
+		i_avg_width = PQfnumber(res, "avg_width");
+		i_n_distinct = PQfnumber(res, "n_distinct");
+		i_most_common_vals = PQfnumber(res, "most_common_vals");
+		i_most_common_freqs = PQfnumber(res, "most_common_freqs");
+		i_histogram_bounds = PQfnumber(res, "histogram_bounds");
+		i_correlation = PQfnumber(res, "correlation");
+		i_most_common_elems = PQfnumber(res, "most_common_elems");
+		i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
+		i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
+		i_range_length_histogram = PQfnumber(res, "range_length_histogram");
+		i_range_empty_frac = PQfnumber(res, "range_empty_frac");
+		i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
+
+		/* restore attribute stats */
+		for (int rownum = 0; rownum < PQntuples(res); rownum++)
 		{
-			appendPQExpBuffer(out, ",\n\t'attname', ");
-			appendStringLiteralAH(out, attname, fout);
-		}
-		else
-		{
-			bool		found = false;
+			const char *attname;
 
-			for (int i = 0; i < rsinfo->nindAttNames; i++)
+			appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
+			appendPQExpBuffer(out, "\t'version', '%u'::integer,\n",
+							fout->remoteVersion);
+			appendPQExpBufferStr(out, "\t'schemaname', ");
+			appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
+			appendPQExpBufferStr(out, ",\n\t'relname', ");
+			appendStringLiteralAH(out, rsinfo->dobj.name, fout);
+
+			if (PQgetisnull(res, rownum, i_attname))
+				pg_fatal("attname cannot be NULL");
+			attname = PQgetvalue(res, rownum, i_attname);
+
+			/*
+			* Indexes look up attname in indAttNames to derive attnum, all others
+			* use attname directly.  We must specify attnum for indexes, since
+			* their attnames are not necessarily stable across dump/reload.
+			*/
+			if (rsinfo->nindAttNames == 0)
 			{
-				if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
+				appendPQExpBuffer(out, ",\n\t'attname', ");
+				appendStringLiteralAH(out, attname, fout);
+			}
+			else
+			{
+				bool		found = false;
+
+				for (int i = 0; i < rsinfo->nindAttNames; i++)
 				{
-					appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
-									  i + 1);
-					found = true;
-					break;
+					if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
+					{
+						appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
+										i + 1);
+						found = true;
+						break;
+					}
 				}
+
+				if (!found)
+					pg_fatal("could not find index attname \"%s\"", attname);
 			}
 
-			if (!found)
-				pg_fatal("could not find index attname \"%s\"", attname);
+			if (!PQgetisnull(res, rownum, i_inherited))
+				appendNamedArgument(out, fout, "inherited", "boolean",
+									PQgetvalue(res, rownum, i_inherited));
+			if (!PQgetisnull(res, rownum, i_null_frac))
+				appendNamedArgument(out, fout, "null_frac", "real",
+									PQgetvalue(res, rownum, i_null_frac));
+			if (!PQgetisnull(res, rownum, i_avg_width))
+				appendNamedArgument(out, fout, "avg_width", "integer",
+									PQgetvalue(res, rownum, i_avg_width));
+			if (!PQgetisnull(res, rownum, i_n_distinct))
+				appendNamedArgument(out, fout, "n_distinct", "real",
+									PQgetvalue(res, rownum, i_n_distinct));
+			if (!PQgetisnull(res, rownum, i_most_common_vals))
+				appendNamedArgument(out, fout, "most_common_vals", "text",
+									PQgetvalue(res, rownum, i_most_common_vals));
+			if (!PQgetisnull(res, rownum, i_most_common_freqs))
+				appendNamedArgument(out, fout, "most_common_freqs", "real[]",
+									PQgetvalue(res, rownum, i_most_common_freqs));
+			if (!PQgetisnull(res, rownum, i_histogram_bounds))
+				appendNamedArgument(out, fout, "histogram_bounds", "text",
+									PQgetvalue(res, rownum, i_histogram_bounds));
+			if (!PQgetisnull(res, rownum, i_correlation))
+				appendNamedArgument(out, fout, "correlation", "real",
+									PQgetvalue(res, rownum, i_correlation));
+			if (!PQgetisnull(res, rownum, i_most_common_elems))
+				appendNamedArgument(out, fout, "most_common_elems", "text",
+									PQgetvalue(res, rownum, i_most_common_elems));
+			if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
+				appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
+									PQgetvalue(res, rownum, i_most_common_elem_freqs));
+			if (!PQgetisnull(res, rownum, i_elem_count_histogram))
+				appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
+									PQgetvalue(res, rownum, i_elem_count_histogram));
+			if (fout->remoteVersion >= 170000)
+			{
+				if (!PQgetisnull(res, rownum, i_range_length_histogram))
+					appendNamedArgument(out, fout, "range_length_histogram", "text",
+										PQgetvalue(res, rownum, i_range_length_histogram));
+				if (!PQgetisnull(res, rownum, i_range_empty_frac))
+					appendNamedArgument(out, fout, "range_empty_frac", "real",
+										PQgetvalue(res, rownum, i_range_empty_frac));
+				if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
+					appendNamedArgument(out, fout, "range_bounds_histogram", "text",
+										PQgetvalue(res, rownum, i_range_bounds_histogram));
+			}
+			appendPQExpBufferStr(out, "\n);\n");
 		}
 
-		if (!PQgetisnull(res, rownum, i_inherited))
-			appendNamedArgument(out, fout, "inherited", "boolean",
-								PQgetvalue(res, rownum, i_inherited));
-		if (!PQgetisnull(res, rownum, i_null_frac))
-			appendNamedArgument(out, fout, "null_frac", "real",
-								PQgetvalue(res, rownum, i_null_frac));
-		if (!PQgetisnull(res, rownum, i_avg_width))
-			appendNamedArgument(out, fout, "avg_width", "integer",
-								PQgetvalue(res, rownum, i_avg_width));
-		if (!PQgetisnull(res, rownum, i_n_distinct))
-			appendNamedArgument(out, fout, "n_distinct", "real",
-								PQgetvalue(res, rownum, i_n_distinct));
-		if (!PQgetisnull(res, rownum, i_most_common_vals))
-			appendNamedArgument(out, fout, "most_common_vals", "text",
-								PQgetvalue(res, rownum, i_most_common_vals));
-		if (!PQgetisnull(res, rownum, i_most_common_freqs))
-			appendNamedArgument(out, fout, "most_common_freqs", "real[]",
-								PQgetvalue(res, rownum, i_most_common_freqs));
-		if (!PQgetisnull(res, rownum, i_histogram_bounds))
-			appendNamedArgument(out, fout, "histogram_bounds", "text",
-								PQgetvalue(res, rownum, i_histogram_bounds));
-		if (!PQgetisnull(res, rownum, i_correlation))
-			appendNamedArgument(out, fout, "correlation", "real",
-								PQgetvalue(res, rownum, i_correlation));
-		if (!PQgetisnull(res, rownum, i_most_common_elems))
-			appendNamedArgument(out, fout, "most_common_elems", "text",
-								PQgetvalue(res, rownum, i_most_common_elems));
-		if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
-			appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
-								PQgetvalue(res, rownum, i_most_common_elem_freqs));
-		if (!PQgetisnull(res, rownum, i_elem_count_histogram))
-			appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
-								PQgetvalue(res, rownum, i_elem_count_histogram));
-		if (fout->remoteVersion >= 170000)
-		{
-			if (!PQgetisnull(res, rownum, i_range_length_histogram))
-				appendNamedArgument(out, fout, "range_length_histogram", "text",
-									PQgetvalue(res, rownum, i_range_length_histogram));
-			if (!PQgetisnull(res, rownum, i_range_empty_frac))
-				appendNamedArgument(out, fout, "range_empty_frac", "real",
-									PQgetvalue(res, rownum, i_range_empty_frac));
-			if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
-				appendNamedArgument(out, fout, "range_bounds_histogram", "text",
-									PQgetvalue(res, rownum, i_range_bounds_histogram));
-		}
-		appendPQExpBufferStr(out, "\n);\n");
+		PQclear(res);
 	}
 
-	PQclear(res);
-
 	ArchiveEntry(fout, nilCatalogId, createDumpId(),
 				 ARCHIVE_OPTS(.tag = dobj->name,
 							  .namespace = dobj->namespace->dobj.name,
-- 
2.48.1