diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 47191be86ad..099d57eef26 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -259,7 +259,7 @@ getSchemaData(Archive *fout, int *numTablesPtr) if (g_verbose) write_msg(NULL, "reading extended statistics\n"); - getExtendedStatistics(fout, tblinfo, numTables); + getExtendedStatistics(fout); if (g_verbose) write_msg(NULL, "reading constraints\n"); diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 03f46bcbeef..3b6bc59b5a9 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3365,6 +3365,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH) strcmp(type, "FOREIGN TABLE") == 0 || strcmp(type, "TEXT SEARCH DICTIONARY") == 0 || strcmp(type, "TEXT SEARCH CONFIGURATION") == 0 || + strcmp(type, "STATISTICS") == 0 || /* non-schema-specified objects */ strcmp(type, "DATABASE") == 0 || strcmp(type, "PROCEDURAL LANGUAGE") == 0 || @@ -3581,6 +3582,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData) strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 || strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 || strcmp(te->desc, "SERVER") == 0 || + strcmp(te->desc, "STATISTICS") == 0 || strcmp(te->desc, "PUBLICATION") == 0 || strcmp(te->desc, "SUBSCRIPTION") == 0) { @@ -3602,8 +3604,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData) strcmp(te->desc, "TRIGGER") == 0 || strcmp(te->desc, "ROW SECURITY") == 0 || strcmp(te->desc, "POLICY") == 0 || - strcmp(te->desc, "USER MAPPING") == 0 || - strcmp(te->desc, "STATISTICS") == 0) + strcmp(te->desc, "USER MAPPING") == 0) { /* these object types don't have separate owners */ } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index f8de0a1f938..34156bfe4e5 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6677,17 +6677,14 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) /* * getExtendedStatistics - * get information about extended statistics on a dumpable table - * or materialized view. + * get information about extended-statistics objects. * * Note: extended statistics data is not returned directly to the caller, but * it does get entered into the DumpableObject tables. */ void -getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables) +getExtendedStatistics(Archive *fout) { - int i, - j; PQExpBuffer query; PGresult *res; StatsExtInfo *statsextinfo; @@ -6695,7 +6692,9 @@ getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables) int i_tableoid; int i_oid; int i_stxname; - int i_stxdef; + int i_stxnamespace; + int i_rolname; + int i; /* Extended statistics were new in v10 */ if (fout->remoteVersion < 100000) @@ -6703,73 +6702,46 @@ getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables) query = createPQExpBuffer(); - for (i = 0; i < numTables; i++) + /* Make sure we are in proper schema */ + selectSourceSchema(fout, "pg_catalog"); + + appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, " + "stxnamespace, (%s stxowner) AS rolname " + "FROM pg_catalog.pg_statistic_ext", + username_subquery); + + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_stxname = PQfnumber(res, "stxname"); + i_stxnamespace = PQfnumber(res, "stxnamespace"); + i_rolname = PQfnumber(res, "rolname"); + + statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo)); + + for (i = 0; i < ntups; i++) { - TableInfo *tbinfo = &tblinfo[i]; + statsextinfo[i].dobj.objType = DO_STATSEXT; + statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid)); + statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&statsextinfo[i].dobj); + statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname)); + statsextinfo[i].dobj.namespace = + findNamespace(fout, + atooid(PQgetvalue(res, i, i_stxnamespace))); + statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname)); - /* - * Only plain tables, materialized views, foreign tables and - * partitioned tables can have extended statistics. - */ - if (tbinfo->relkind != RELKIND_RELATION && - tbinfo->relkind != RELKIND_MATVIEW && - tbinfo->relkind != RELKIND_FOREIGN_TABLE && - tbinfo->relkind != RELKIND_PARTITIONED_TABLE) - continue; + /* Decide whether we want to dump it */ + selectDumpableObject(&(statsextinfo[i].dobj), fout); - /* - * Ignore extended statistics of tables whose definitions are not to - * be dumped. - */ - if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) - continue; - - if (g_verbose) - write_msg(NULL, "reading extended statistics for table \"%s.%s\"\n", - tbinfo->dobj.namespace->dobj.name, - tbinfo->dobj.name); - - /* Make sure we are in proper schema so stadef is right */ - selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name); - - resetPQExpBuffer(query); - - appendPQExpBuffer(query, - "SELECT " - "tableoid, " - "oid, " - "stxname, " - "pg_catalog.pg_get_statisticsobjdef(oid) AS stxdef " - "FROM pg_catalog.pg_statistic_ext " - "WHERE stxrelid = '%u' " - "ORDER BY stxname", tbinfo->dobj.catId.oid); - - res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - - ntups = PQntuples(res); - - i_tableoid = PQfnumber(res, "tableoid"); - i_oid = PQfnumber(res, "oid"); - i_stxname = PQfnumber(res, "stxname"); - i_stxdef = PQfnumber(res, "stxdef"); - - statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo)); - - for (j = 0; j < ntups; j++) - { - statsextinfo[j].dobj.objType = DO_STATSEXT; - statsextinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid)); - statsextinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid)); - AssignDumpId(&statsextinfo[j].dobj); - statsextinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_stxname)); - statsextinfo[j].dobj.namespace = tbinfo->dobj.namespace; - statsextinfo[j].statsexttable = tbinfo; - statsextinfo[j].statsextdef = pg_strdup(PQgetvalue(res, j, i_stxdef)); - } - - PQclear(res); + /* Stats objects do not currently have ACLs. */ + statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL; } + PQclear(res); destroyPQExpBuffer(query); } @@ -15980,25 +15952,41 @@ static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo) { DumpOptions *dopt = fout->dopt; - TableInfo *tbinfo = statsextinfo->statsexttable; PQExpBuffer q; PQExpBuffer delq; PQExpBuffer labelq; + PQExpBuffer query; + PGresult *res; + char *stxdef; - if (dopt->dataOnly) + /* Skip if not to be dumped */ + if (!statsextinfo->dobj.dump || dopt->dataOnly) return; q = createPQExpBuffer(); delq = createPQExpBuffer(); labelq = createPQExpBuffer(); + query = createPQExpBuffer(); + + /* Make sure we are in proper schema so references are qualified */ + selectSourceSchema(fout, statsextinfo->dobj.namespace->dobj.name); + + appendPQExpBuffer(query, "SELECT " + "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)", + statsextinfo->dobj.catId.oid); + + res = ExecuteSqlQueryForSingleRow(fout, query->data); + + stxdef = PQgetvalue(res, 0, 0); appendPQExpBuffer(labelq, "STATISTICS %s", fmtId(statsextinfo->dobj.name)); - appendPQExpBuffer(q, "%s;\n", statsextinfo->statsextdef); + /* Result of pg_get_statisticsobjdef is complete except for semicolon */ + appendPQExpBuffer(q, "%s;\n", stxdef); appendPQExpBuffer(delq, "DROP STATISTICS %s.", - fmtId(tbinfo->dobj.namespace->dobj.name)); + fmtId(statsextinfo->dobj.namespace->dobj.name)); appendPQExpBuffer(delq, "%s;\n", fmtId(statsextinfo->dobj.name)); @@ -16006,9 +15994,9 @@ dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo) ArchiveEntry(fout, statsextinfo->dobj.catId, statsextinfo->dobj.dumpId, statsextinfo->dobj.name, - tbinfo->dobj.namespace->dobj.name, + statsextinfo->dobj.namespace->dobj.name, NULL, - tbinfo->rolname, false, + statsextinfo->rolname, false, "STATISTICS", SECTION_POST_DATA, q->data, delq->data, NULL, NULL, 0, @@ -16017,14 +16005,16 @@ dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo) /* Dump Statistics Comments */ if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT) dumpComment(fout, labelq->data, - tbinfo->dobj.namespace->dobj.name, - tbinfo->rolname, + statsextinfo->dobj.namespace->dobj.name, + statsextinfo->rolname, statsextinfo->dobj.catId, 0, statsextinfo->dobj.dumpId); + PQclear(res); destroyPQExpBuffer(q); destroyPQExpBuffer(delq); destroyPQExpBuffer(labelq); + destroyPQExpBuffer(query); } /* diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index e7593e6da7f..941080cc753 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -369,8 +369,7 @@ typedef struct _indxInfo typedef struct _statsExtInfo { DumpableObject dobj; - TableInfo *statsexttable; /* link to table the stats ext is for */ - char *statsextdef; + char *rolname; /* name of owner, or empty string */ } StatsExtInfo; typedef struct _ruleInfo @@ -683,7 +682,7 @@ extern TableInfo *getTables(Archive *fout, int *numTables); extern void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables); extern InhInfo *getInherits(Archive *fout, int *numInherits); extern void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables); -extern void getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables); +extern void getExtendedStatistics(Archive *fout); extern void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables); extern RuleInfo *getRules(Archive *fout, int *numRules); extern void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index c492fbdc24d..3f703d6a969 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1420,7 +1420,7 @@ my %tests = ( 'ALTER ... OWNER commands (except post-data objects)' => { all_runs => 0, # catch-all regexp => -qr/^ALTER (?!EVENT TRIGGER|LARGE OBJECT|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO .*;/m, +qr/^ALTER (?!EVENT TRIGGER|LARGE OBJECT|STATISTICS|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO .*;/m, like => {}, # use more-specific options above unlike => { column_inserts => 1,