From 5ea8a35a1d6db14046bb2fb76dfcdddb1bcf9479 Mon Sep 17 00:00:00 2001 From: Corey Huinker 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