diff options
Diffstat (limited to 'src/bin/pg_dump/pg_dump.c')
| -rw-r--r-- | src/bin/pg_dump/pg_dump.c | 273 |
1 files changed, 172 insertions, 101 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 0de6c959bb0..7c38c89bf08 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6819,7 +6819,8 @@ getFuncs(Archive *fout) */ static RelStatsInfo * getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages, - float reltuples, int32 relallvisible, char relkind) + float reltuples, int32 relallvisible, char relkind, + char **indAttNames, int nindAttNames) { if (!fout->dopt->dumpStatistics) return NULL; @@ -6848,6 +6849,8 @@ getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages, info->reltuples = reltuples; info->relallvisible = relallvisible; info->relkind = relkind; + info->indAttNames = indAttNames; + info->nindAttNames = nindAttNames; info->postponed_def = false; return info; @@ -7249,7 +7252,8 @@ getTables(Archive *fout, int *numTables) /* Add statistics */ if (tblinfo[i].interesting) getRelationStatistics(fout, &tblinfo[i].dobj, tblinfo[i].relpages, - reltuples, relallvisible, tblinfo[i].relkind); + reltuples, relallvisible, tblinfo[i].relkind, + NULL, 0); /* * Read-lock target tables to make sure they aren't DROPPED or altered @@ -7534,6 +7538,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_contableoid, i_conoid, i_condef, + i_indattnames, i_tablespace, i_indreloptions, i_indstatcols, @@ -7579,6 +7584,11 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "c.tableoid AS contableoid, " "c.oid AS conoid, " "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, " + "CASE WHEN i.indexprs IS NOT NULL THEN " + "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)" + " FROM pg_catalog.pg_attribute " + " WHERE attrelid = i.indexrelid) " + "ELSE NULL END AS indattnames, " "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "t.reloptions AS indreloptions, "); @@ -7698,6 +7708,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_contableoid = PQfnumber(res, "contableoid"); i_conoid = PQfnumber(res, "conoid"); i_condef = PQfnumber(res, "condef"); + i_indattnames = PQfnumber(res, "indattnames"); i_tablespace = PQfnumber(res, "tablespace"); i_indreloptions = PQfnumber(res, "indreloptions"); i_indstatcols = PQfnumber(res, "indstatcols"); @@ -7714,6 +7725,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) { Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid)); TableInfo *tbinfo = NULL; + char **indAttNames = NULL; + int nindAttNames = 0; int numinds; /* Count rows for this table */ @@ -7784,10 +7797,18 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) else indexkind = RELKIND_PARTITIONED_INDEX; - contype = *(PQgetvalue(res, j, i_contype)); + if (!PQgetisnull(res, j, i_indattnames)) + { + if (!parsePGArray(PQgetvalue(res, j, i_indattnames), + &indAttNames, &nindAttNames)) + pg_fatal("could not parse %s array", "indattnames"); + } + relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages, - reltuples, relallvisible, indexkind); + reltuples, relallvisible, indexkind, + indAttNames, nindAttNames); + contype = *(PQgetvalue(res, j, i_contype)); if (contype == 'p' || contype == 'u' || contype == 'x') { /* @@ -10411,28 +10432,6 @@ dumpComment(Archive *fout, const char *type, } /* - * Tabular description of the parameters to pg_restore_attribute_stats() - * param_name, param_type - */ -static const char *att_stats_arginfo[][2] = { - {"attname", "name"}, - {"inherited", "boolean"}, - {"null_frac", "float4"}, - {"avg_width", "integer"}, - {"n_distinct", "float4"}, - {"most_common_vals", "text"}, - {"most_common_freqs", "float4[]"}, - {"histogram_bounds", "text"}, - {"correlation", "float4"}, - {"most_common_elems", "text"}, - {"most_common_elem_freqs", "float4[]"}, - {"elem_count_histogram", "float4[]"}, - {"range_length_histogram", "text"}, - {"range_empty_frac", "float4"}, - {"range_bounds_histogram", "text"}, -}; - -/* * appendNamedArgument -- * * Convenience routine for constructing parameters of the form: @@ -10440,9 +10439,9 @@ static const char *att_stats_arginfo[][2] = { */ static void appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname, - const char *argval, const char *argtype) + const char *argtype, const char *argval) { - appendPQExpBufferStr(out, "\t"); + appendPQExpBufferStr(out, ",\n\t"); appendStringLiteralAH(out, argname, fout); appendPQExpBufferStr(out, ", "); @@ -10452,68 +10451,6 @@ appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname, } /* - * appendRelStatsImport -- - * - * Append a formatted pg_restore_relation_stats statement. - */ -static void -appendRelStatsImport(PQExpBuffer out, Archive *fout, const RelStatsInfo *rsinfo, - const char *qualified_name) -{ - char reltuples_str[FLOAT_SHORTEST_DECIMAL_LEN]; - - float_to_shortest_decimal_buf(rsinfo->reltuples, reltuples_str); - - appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n"); - appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", - fout->remoteVersion); - appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", qualified_name); - appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages); - appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", reltuples_str); - appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer\n);\n", - rsinfo->relallvisible); -} - -/* - * appendAttStatsImport -- - * - * Append a series of formatted pg_restore_attribute_stats statements. - */ -static void -appendAttStatsImport(PQExpBuffer out, Archive *fout, PGresult *res, - const char *qualified_name) -{ - for (int rownum = 0; rownum < PQntuples(res); rownum++) - { - const char *sep = ""; - - appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n"); - appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", - fout->remoteVersion); - appendPQExpBuffer(out, "\t'relation', '%s'::regclass,\n", - qualified_name); - for (int argno = 0; argno < lengthof(att_stats_arginfo); argno++) - { - const char *argname = att_stats_arginfo[argno][0]; - const char *argtype = att_stats_arginfo[argno][1]; - int fieldno = PQfnumber(res, argname); - - if (fieldno < 0) - pg_fatal("attribute stats export query missing field '%s'", - argname); - - if (PQgetisnull(res, rownum, fieldno)) - continue; - - appendPQExpBufferStr(out, sep); - appendNamedArgument(out, fout, argname, PQgetvalue(res, rownum, fieldno), argtype); - sep = ",\n"; - } - appendPQExpBufferStr(out, "\n);\n"); - } -} - -/* * Decide which section to use based on the relkind of the parent object. * * NB: materialized views may be postponed from SECTION_PRE_DATA to @@ -10549,14 +10486,30 @@ statisticsDumpSection(const RelStatsInfo *rsinfo) static void dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) { + const DumpableObject *dobj = &rsinfo->dobj; PGresult *res; PQExpBuffer query; PQExpBuffer out; PQExpBuffer tag; - DumpableObject *dobj = (DumpableObject *) &rsinfo->dobj; DumpId *deps = NULL; int ndeps = 0; - const char *qualified_name; + char *qualified_name; + char reltuples_str[FLOAT_SHORTEST_DECIMAL_LEN]; + int i_attname; + int i_inherited; + int i_null_frac; + int i_avg_width; + int i_n_distinct; + int i_most_common_vals; + int i_most_common_freqs; + int i_histogram_bounds; + int i_correlation; + int i_most_common_elems; + int i_most_common_elem_freqs; + int i_elem_count_histogram; + int i_range_length_histogram; + int i_range_empty_frac; + int i_range_bounds_histogram; /* nothing to do if we are not dumping statistics */ if (!fout->dopt->dumpStatistics) @@ -10586,7 +10539,8 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) if (fout->remoteVersion >= 170000) appendPQExpBufferStr(query, - "s.range_length_histogram, s.range_empty_frac, " + "s.range_length_histogram, " + "s.range_empty_frac, " "s.range_bounds_histogram "); else appendPQExpBufferStr(query, @@ -10595,7 +10549,7 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) "NULL AS range_bounds_histogram "); appendPQExpBufferStr(query, - "FROM pg_stats s " + "FROM pg_catalog.pg_stats s " "WHERE s.schemaname = $1 " "AND s.tablename = $2 " "ORDER BY s.attname, s.inherited"); @@ -10606,21 +10560,137 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) resetPQExpBuffer(query); } + out = createPQExpBuffer(); + + qualified_name = pg_strdup(fmtQualifiedDumpable(rsinfo)); + + /* restore relation stats */ + appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n"); + appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", + fout->remoteVersion); + appendPQExpBufferStr(out, "\t'relation', "); + appendStringLiteralAH(out, qualified_name, fout); + appendPQExpBufferStr(out, "::regclass,\n"); + appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages); + float_to_shortest_decimal_buf(rsinfo->reltuples, reltuples_str); + appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", reltuples_str); + 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, "); "); + appendPQExpBufferStr(query, ");"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - out = createPQExpBuffer(); + 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++) + { + const char *attname; - qualified_name = fmtQualifiedId(rsinfo->dobj.namespace->dobj.name, - rsinfo->dobj.name); + appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n"); + appendPQExpBuffer(out, "\t'version', '%u'::integer,\n", + fout->remoteVersion); + appendPQExpBufferStr(out, "\t'relation', "); + appendStringLiteralAH(out, qualified_name, fout); + appendPQExpBufferStr(out, "::regclass"); + + 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) + appendNamedArgument(out, fout, "attname", "name", attname); + else + { + bool found = false; + + for (int i = 0; i < rsinfo->nindAttNames; i++) + { + if (strcmp(attname, rsinfo->indAttNames[i]) == 0) + { + appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint", + i + 1); + found = true; + break; + } + } - appendRelStatsImport(out, fout, rsinfo, qualified_name); - appendAttStatsImport(out, fout, res, qualified_name); + 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"); + } PQclear(res); @@ -10634,8 +10704,9 @@ dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo) .deps = deps, .nDeps = ndeps)); - destroyPQExpBuffer(query); + free(qualified_name); destroyPQExpBuffer(out); + destroyPQExpBuffer(query); destroyPQExpBuffer(tag); } |
