v38-0001-make-statistics-dumped-at-SECTION_POST_DATA.no-cfbot
application/octet-stream
Filename: v38-0001-make-statistics-dumped-at-SECTION_POST_DATA.no-cfbot
Type: application/octet-stream
Part: 0
Message:
Re: Statistics Import and Export
From aa78d861024b409bf63121dedf9dd955ad9dc734 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Mon, 20 Jan 2025 16:12:40 +0800
Subject: [PATCH v38 1/1] make statistics dumped at SECTION_POST_DATA
based on v38-0001-Enable-dumping-of-table-index-stats-in-pg_dump.patch
refactoring make statistics dump in the SECTION_POST_DATA.
---
doc/src/sgml/ref/pg_dump.sgml | 58 +++-
doc/src/sgml/ref/pg_dumpall.sgml | 38 +++
doc/src/sgml/ref/pg_restore.sgml | 51 +++-
doc/src/sgml/ref/pgupgrade.sgml | 18 ++
src/bin/pg_dump/common.c | 3 +
src/bin/pg_dump/pg_backup.h | 2 +
src/bin/pg_dump/pg_backup_archiver.c | 22 +-
src/bin/pg_dump/pg_dump.c | 383 ++++++++++++++++++++++++++-
src/bin/pg_dump/pg_dump.h | 8 +
src/bin/pg_dump/pg_dump_sort.c | 11 +-
src/bin/pg_dump/pg_dumpall.c | 5 +
src/bin/pg_dump/pg_restore.c | 38 ++-
src/bin/pg_dump/t/001_basic.pl | 18 ++
src/bin/pg_dump/t/002_pg_dump.pl | 62 ++++-
src/bin/pg_upgrade/dump.c | 6 +-
src/bin/pg_upgrade/option.c | 12 +
src/bin/pg_upgrade/pg_upgrade.h | 1 +
src/tools/pgindent/typedefs.list | 1 +
18 files changed, 705 insertions(+), 32 deletions(-)
diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index d66e901f51b..3f663915422 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -123,7 +123,7 @@ PostgreSQL documentation
<term><option>--data-only</option></term>
<listitem>
<para>
- Dump only the data, not the schema (data definitions).
+ Dump only the data, not the schema (data definitions) or statistics.
Table data, large objects, and sequence values are dumped.
</para>
@@ -141,13 +141,11 @@ PostgreSQL documentation
<listitem>
<para>
Include large objects in the dump. This is the default behavior
- except when <option>--schema</option>, <option>--table</option>, or
- <option>--schema-only</option> is specified. The <option>-b</option>
- switch is therefore only useful to add large objects to dumps
- where a specific schema or table has been requested. Note that
- large objects are considered data and therefore will be included when
- <option>--data-only</option> is used, but not
- when <option>--schema-only</option> is.
+ except when <option>--schema</option>, <option>--table</option>,
+ <option>--schema-only</option>, or <option>--statistics-only</option>, or
+ <option>--no-data</option> is specified. The <option>-b</option>
+ switch is therefore only useful to add large objects to dumps where a
+ specific schema or table has been requested.
</para>
</listitem>
</varlistentry>
@@ -516,10 +514,11 @@ PostgreSQL documentation
<term><option>--schema-only</option></term>
<listitem>
<para>
- Dump only the object definitions (schema), not data.
+ Dump only the object definitions (schema), not data or statistics.
</para>
<para>
- This option is the inverse of <option>--data-only</option>.
+ This option is mutually exclusive to <option>--data-only</option>
+ and <option>--statistics-only</option>.
It is similar to, but for historical reasons not identical to,
specifying
<option>--section=pre-data --section=post-data</option>.
@@ -652,6 +651,18 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-X</option></term>
+ <term><option>--statistics-only</option></term>
+ <listitem>
+ <para>
+ Dump only the statistics, not the schema (data definitions) or data.
+ Statistics for tables, materialized views, and indexes are dumped.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-Z <replaceable class="parameter">level</replaceable></option></term>
<term><option>-Z <replaceable class="parameter">method</replaceable></option>[:<replaceable>detail</replaceable>]</term>
@@ -1080,6 +1091,15 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-data</option></term>
+ <listitem>
+ <para>
+ Do not dump data.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-publications</option></term>
<listitem>
@@ -1098,6 +1118,24 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-schema</option></term>
+ <listitem>
+ <para>
+ Do not dump schema (data definitions).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-statistics</option></term>
+ <listitem>
+ <para>
+ Do not dump statistics.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-subscriptions</option></term>
<listitem>
diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml
index 014f2792589..d423153a93a 100644
--- a/doc/src/sgml/ref/pg_dumpall.sgml
+++ b/doc/src/sgml/ref/pg_dumpall.sgml
@@ -265,6 +265,17 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-X</option></term>
+ <term><option>--statistics-only</option></term>
+ <listitem>
+ <para>
+ Dump only the statistics, not the schema (data definitions) or data.
+ Statistics for tables, materialized views, and indexes are dumped.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--binary-upgrade</option></term>
<listitem>
@@ -422,6 +433,15 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-data</option></term>
+ <listitem>
+ <para>
+ Do not dump data.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-publications</option></term>
<listitem>
@@ -447,6 +467,15 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-schema</option></term>
+ <listitem>
+ <para>
+ Do not dump schema (data definitions).
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-security-labels</option></term>
<listitem>
@@ -456,6 +485,15 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-statistics</option></term>
+ <listitem>
+ <para>
+ Do not dump statistics.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-subscriptions</option></term>
<listitem>
diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml
index b8b27e1719e..22c3c118add 100644
--- a/doc/src/sgml/ref/pg_restore.sgml
+++ b/doc/src/sgml/ref/pg_restore.sgml
@@ -94,7 +94,7 @@ PostgreSQL documentation
<term><option>--data-only</option></term>
<listitem>
<para>
- Restore only the data, not the schema (data definitions).
+ Restore only the data, not the schema (data definitions) or statistics.
Table data, large objects, and sequence values are restored,
if present in the archive.
</para>
@@ -483,10 +483,11 @@ PostgreSQL documentation
to the extent that schema entries are present in the archive.
</para>
<para>
- This option is the inverse of <option>--data-only</option>.
+ This option is mutually exclusive of <option>--data-only</option>
+ and <option>--statistics-only</option>.
It is similar to, but for historical reasons not identical to,
specifying
- <option>--section=pre-data --section=post-data</option>.
+ <option>--section=pre-data --section=post-data --no-statistics</option>.
</para>
<para>
(Do not confuse this with the <option>--schema</option> option, which
@@ -599,6 +600,20 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-X</option></term>
+ <term><option>--statistics-only</option></term>
+ <listitem>
+ <para>
+ Restore only the statistics, not schema (data definitions) or data.
+ </para>
+ <para>
+ (Do not confuse this with the <option>--schema</option> option, which
+ uses the word <quote>schema</quote> in a different meaning.)
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-1</option></term>
<term><option>--single-transaction</option></term>
@@ -681,6 +696,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-data</option></term>
+ <listitem>
+ <para>
+ Do not output commands to restore data, even if the archive
+ contains them.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-data-for-failed-tables</option></term>
<listitem>
@@ -713,6 +738,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-schema</option></term>
+ <listitem>
+ <para>
+ Do not output commands to restore schema (data definitions), even if
+ the archive contains them.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-security-labels</option></term>
<listitem>
@@ -723,6 +758,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-statistics</option></term>
+ <listitem>
+ <para>
+ Do not output commands to restore statistics, even if the archive
+ contains them.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-subscriptions</option></term>
<listitem>
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 4777381dac2..64a1ebd613b 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -145,6 +145,24 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--with-statistics</option></term>
+ <listitem>
+ <para>
+ Restore statistics from the old cluster into the new cluster.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-statistics</option></term>
+ <listitem>
+ <para>
+ Do not restore statistics from the old cluster into the new cluster.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-o</option> <replaceable class="parameter">options</replaceable></term>
<term><option>--old-options</option> <replaceable class="parameter">options</replaceable></term>
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 56b6c368acf..bc856492cc8 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -216,6 +216,9 @@ getSchemaData(Archive *fout, int *numTablesPtr)
pg_log_info("flagging indexes in partitioned tables");
flagInhIndexes(fout, tblinfo, numTables);
+ pg_log_info("reading table statistics");
+ getRelationStatistics(fout, tblinfo, numTables);
+
pg_log_info("reading extended statistics");
getExtendedStatistics(fout);
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index f0f19bb0b29..350cf659c41 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -160,6 +160,7 @@ typedef struct _restoreOptions
/* flags derived from the user-settable flags */
bool dumpSchema;
bool dumpData;
+ bool dumpStatistics;
} RestoreOptions;
typedef struct _dumpOptions
@@ -208,6 +209,7 @@ typedef struct _dumpOptions
/* flags derived from the user-settable flags */
bool dumpSchema;
bool dumpData;
+ bool dumpStatistics;
} DumpOptions;
/*
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 707a3fc844c..b190d9731f6 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -46,7 +46,6 @@
#define TEXT_DUMP_HEADER "--\n-- PostgreSQL database dump\n--\n\n"
#define TEXT_DUMPALL_HEADER "--\n-- PostgreSQL database cluster dump\n--\n\n"
-
static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
const pg_compress_specification compression_spec,
bool dosync, ArchiveMode mode,
@@ -149,6 +148,7 @@ InitDumpOptions(DumpOptions *opts)
opts->dumpSections = DUMP_UNSECTIONED;
opts->dumpSchema = true;
opts->dumpData = true;
+ opts->dumpStatistics = true;
}
/*
@@ -169,9 +169,10 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
dopt->outputClean = ropt->dropSchema;
dopt->dumpData = ropt->dumpData;
dopt->dumpSchema = ropt->dumpSchema;
+ dopt->dumpSections = ropt->dumpSections;
+ dopt->dumpStatistics = ropt->dumpStatistics;
dopt->if_exists = ropt->if_exists;
dopt->column_inserts = ropt->column_inserts;
- dopt->dumpSections = ropt->dumpSections;
dopt->aclsSkip = ropt->aclsSkip;
dopt->outputSuperuser = ropt->superuser;
dopt->outputCreateDB = ropt->createDB;
@@ -1084,6 +1085,7 @@ NewRestoreOptions(void)
opts->compression_spec.level = 0;
opts->dumpSchema = true;
opts->dumpData = true;
+ opts->dumpStatistics = true;
return opts;
}
@@ -1093,6 +1095,7 @@ _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te)
{
RestoreOptions *ropt = AH->public.ropt;
+ ahprintf(AH, "-- ALTER TABLE DISABLE TRIGGER ALL %d %d; \n\n", ropt->dumpSchema, ropt->disable_triggers);
/* This hack is only needed in a data-only restore */
if (ropt->dumpSchema || !ropt->disable_triggers)
return;
@@ -2962,6 +2965,18 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
if (ropt->no_subscriptions && strcmp(te->desc, "SUBSCRIPTION") == 0)
return 0;
+ /*
+ * statistics is in the REQ_DATA section. we can choose to ignore it, but
+ * not when we request dump statistics
+ */
+ if (strcmp(te->desc, "STATISTICS DATA") == 0)
+ {
+ if (!ropt->dumpStatistics)
+ return 0;
+ else
+ return REQ_DATA;
+ }
+
/* Ignore it if section is not to be dumped/restored */
switch (curSection)
{
@@ -3196,7 +3211,8 @@ _tocEntryRestorePass(TocEntry *te)
strcmp(te->desc, "DEFAULT ACL") == 0)
return RESTORE_PASS_ACL;
if (strcmp(te->desc, "EVENT TRIGGER") == 0 ||
- strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0)
+ strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0 ||
+ strcmp(te->desc, "STATISTICS DATA") == 0 )
return RESTORE_PASS_POST_ACL;
/*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 8f73a5df956..19a08f8d08d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -430,7 +430,11 @@ main(int argc, char **argv)
DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
bool data_only = false;
bool schema_only = false;
+ bool statistics_only = false;
+ static int no_data = 0;
+ static int no_schema = 0;
+ static int no_statistics = 0;
static DumpOptions dopt;
static struct option long_options[] = {
@@ -466,6 +470,7 @@ main(int argc, char **argv)
{"encoding", required_argument, NULL, 'E'},
{"help", no_argument, NULL, '?'},
{"version", no_argument, NULL, 'V'},
+ {"statistics-only", no_argument, NULL, 'X'},
/*
* the following options don't have an equivalent short option letter
@@ -492,8 +497,11 @@ main(int argc, char **argv)
{"strict-names", no_argument, &strict_names, 1},
{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
{"no-comments", no_argument, &dopt.no_comments, 1},
+ {"no-data", no_argument, &no_data, 1},
{"no-publications", no_argument, &dopt.no_publications, 1},
+ {"no-schema", no_argument, &no_schema, 1},
{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
+ {"no-statistics", no_argument, &no_statistics, 1},
{"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
{"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
{"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
@@ -539,7 +547,7 @@ main(int argc, char **argv)
InitDumpOptions(&dopt);
- while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
+ while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:PRsS:t:T:U:vwWxXZ:",
long_options, &optindex)) != -1)
{
switch (c)
@@ -613,6 +621,10 @@ main(int argc, char **argv)
dopt.cparams.pgport = pg_strdup(optarg);
break;
+ case 'X': /* Dump statistics only */
+ statistics_only = true;
+ break;
+
case 'R':
/* no-op, still accepted for backwards compatibility */
break;
@@ -784,6 +796,17 @@ main(int argc, char **argv)
if (data_only && schema_only)
pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
+ if (schema_only && statistics_only)
+ pg_fatal("options -s/--schema-only and -X/--statistics-only cannot be used together");
+ if (data_only && statistics_only)
+ pg_fatal("options -a/--data-only and -X/--statistics-only cannot be used together");
+
+ if (data_only && no_data)
+ pg_fatal("options -a/--data-only and --no-data cannot be used together");
+ if (schema_only && no_schema)
+ pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
+ if (statistics_only && no_statistics)
+ pg_fatal("options -X/--statistics-only and --no-statistics cannot be used together");
if (schema_only && foreign_servers_include_patterns.head != NULL)
pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
@@ -798,8 +821,17 @@ main(int argc, char **argv)
pg_fatal("option --if-exists requires option -c/--clean");
/* set derivative flags */
- dopt.dumpSchema = (!data_only);
- dopt.dumpData = (!schema_only);
+ dopt.dumpData = data_only || (!schema_only && !statistics_only);
+ dopt.dumpSchema = schema_only || (!data_only && !statistics_only);
+ dopt.dumpStatistics = statistics_only || (!data_only && !schema_only);
+
+ if (no_data)
+ dopt.dumpData = false;
+ if (no_schema)
+ dopt.dumpSchema = false;
+ if (no_statistics ||
+ (dopt.dumpSections && (!(dopt.dumpSections & DUMP_POST_DATA))))
+ dopt.dumpStatistics = false;
/*
* --inserts are already implied above if --column-inserts or
@@ -1099,6 +1131,7 @@ main(int argc, char **argv)
ropt->dropSchema = dopt.outputClean;
ropt->dumpData = dopt.dumpData;
ropt->dumpSchema = dopt.dumpSchema;
+ ropt->dumpStatistics = dopt.dumpStatistics;
ropt->if_exists = dopt.if_exists;
ropt->column_inserts = dopt.column_inserts;
ropt->dumpSections = dopt.dumpSections;
@@ -1177,7 +1210,7 @@ help(const char *progname)
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nOptions controlling the output content:\n"));
- printf(_(" -a, --data-only dump only the data, not the schema\n"));
+ printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
printf(_(" -b, --large-objects include large objects in dump\n"));
printf(_(" --blobs (same as --large-objects, deprecated)\n"));
printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
@@ -1190,11 +1223,12 @@ help(const char *progname)
printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
printf(_(" -O, --no-owner skip restoration of object ownership in\n"
" plain-text format\n"));
- printf(_(" -s, --schema-only dump only the schema, no data\n"));
+ printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
+ printf(_(" -X, --statistics-only dump only the statistics, not schema or data\n"));
printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
@@ -1219,8 +1253,11 @@ help(const char *progname)
printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
printf(_(" --load-via-partition-root load partitions via the root table\n"));
printf(_(" --no-comments do not dump comment commands\n"));
+ printf(_(" --no-data do not dump data\n"));
printf(_(" --no-publications do not dump publications\n"));
+ printf(_(" --no-schema do not dump schema\n"));
printf(_(" --no-security-labels do not dump security label assignments\n"));
+ printf(_(" --no-statistics do not dump statistics\n"));
printf(_(" --no-subscriptions do not dump subscriptions\n"));
printf(_(" --no-table-access-method do not dump table access methods\n"));
printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
@@ -6777,6 +6814,85 @@ getFuncs(Archive *fout)
destroyPQExpBuffer(query);
}
+/*
+ * getRelationStatistics
+ * get information about all statistics on dumpable relations.
+ */
+void
+getRelationStatistics(Archive *fout, TableInfo tblinfo[], int numTables)
+{
+ int i = 0;
+ int j = 0;
+ int tbl_cnt = 0;
+ int index_cnt = 0;
+ RelStatsInfo *rel_stats_info = NULL;
+ TableInfo *tbinfo = NULL;
+ IndxInfo *indxinfo = NULL;
+ Oid *tabldids = NULL;
+
+ if (!fout->dopt->dumpStatistics)
+ return;
+
+ tabldids = pg_malloc0(numTables * sizeof(Oid));
+ for (i = 0; i < numTables; i++)
+ {
+ tbinfo = &tblinfo[i];
+ /*
+ * we only dump statistics related to regular relations, partitioned
+ * tables, materialized views
+ */
+ if (!(tbinfo->relkind == RELKIND_RELATION ||
+ tbinfo->relkind == RELKIND_MATVIEW ||
+ tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
+ continue;
+
+ if (!tbinfo->interesting)
+ continue;
+
+ tabldids[tbl_cnt] = tbinfo->dobj.catId.oid;
+ index_cnt = index_cnt + tbinfo->numIndexes;
+ tbl_cnt++;
+ }
+
+ if(tbl_cnt == 0)
+ {
+ free(tabldids);
+ return;
+ }
+
+ /*
+ * since we dump indexes statistics, we need iterate over TableInfo->indexes
+ */
+ rel_stats_info = pg_malloc((tbl_cnt + index_cnt) * sizeof(RelStatsInfo));
+ for (i = 0; i < tbl_cnt; i++)
+ {
+ tbinfo = findTableByOid(tabldids[i]);
+ rel_stats_info[j].dobj.objType = DO_REL_STATS;
+ rel_stats_info[j].dobj.catId.tableoid = 0;
+ rel_stats_info[j].dobj.catId.oid = tbinfo->dobj.catId.oid;
+ AssignDumpId(&rel_stats_info[j].dobj);
+ rel_stats_info[j].dobj.namespace = tbinfo->dobj.namespace;
+ rel_stats_info[j].dobj.name = pg_strdup(tbinfo->dobj.name);
+ rel_stats_info[j].stat_relation = tbinfo;
+
+ for (int k = 0; k < tbinfo->numIndexes; k++)
+ {
+ j++;
+ indxinfo = (&(tbinfo->indexes)[k]);
+ rel_stats_info[j].dobj.objType = DO_REL_STATS;
+ rel_stats_info[j].dobj.catId.tableoid = 0;
+ rel_stats_info[j].dobj.catId.oid = indxinfo->dobj.catId.oid;
+ AssignDumpId(&rel_stats_info[j].dobj);
+ rel_stats_info[j].dobj.namespace = indxinfo->dobj.namespace;
+ rel_stats_info[j].dobj.name = pg_strdup(indxinfo->dobj.name);
+ rel_stats_info[j].stat_relation = tbinfo;
+ }
+ j++;
+ }
+ Assert(j == tbl_cnt + index_cnt);
+ free(tabldids);
+}
+
/*
* getTables
* read all the tables (no indexes) in the system catalogs,
@@ -10296,6 +10412,259 @@ dumpComment(Archive *fout, const char *type,
catalogId, subid, dumpId, NULL);
}
+/*
+ * Tabular description of the parameters to pg_restore_relation_stats()
+ * param_name, param_type
+ */
+static const char *rel_stats_arginfo[][2] = {
+ {"relation", "regclass"},
+ {"version", "integer"},
+ {"relpages", "integer"},
+ {"reltuples", "real"},
+ {"relallvisible", "integer"},
+};
+
+/*
+ * Tabular description of the parameters to pg_restore_attribute_stats()
+ * param_name, param_type
+ */
+static const char *att_stats_arginfo[][2] = {
+ {"relation", "regclass"},
+ {"attname", "name"},
+ {"inherited", "boolean"},
+ {"version", "integer"},
+ {"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"},
+};
+
+/*
+ * getRelStatsExportQuery --
+ *
+ * Generate a query that will fetch all relation (e.g. pg_class)
+ * stats for a given relation.
+ */
+static void
+getRelStatsExportQuery(PQExpBuffer query, Archive *fout,
+ const char *schemaname, const char *relname)
+{
+ resetPQExpBuffer(query);
+ appendPQExpBufferStr(query,
+ "SELECT c.oid::regclass AS relation, "
+ "current_setting('server_version_num') AS version, "
+ "c.relpages, c.reltuples, c.relallvisible "
+ "FROM pg_class c "
+ "JOIN pg_namespace n "
+ "ON n.oid = c.relnamespace "
+ "WHERE n.nspname = ");
+ appendStringLiteralAH(query, schemaname, fout);
+ appendPQExpBufferStr(query, " AND c.relname = ");
+ appendStringLiteralAH(query, relname, fout);
+}
+
+/*
+ * getAttStatsExportQuery --
+ *
+ * Generate a query that will fetch all attribute (e.g. pg_statistic)
+ * stats for a given relation.
+ */
+static void
+getAttStatsExportQuery(PQExpBuffer query, Archive *fout,
+ const char *schemaname, const char *relname)
+{
+ resetPQExpBuffer(query);
+ appendPQExpBufferStr(query,
+ "SELECT c.oid::regclass AS relation, "
+ "s.attname,"
+ "s.inherited,"
+ "current_setting('server_version_num') AS version, "
+ "s.null_frac,"
+ "s.avg_width,"
+ "s.n_distinct,"
+ "s.most_common_vals,"
+ "s.most_common_freqs,"
+ "s.histogram_bounds,"
+ "s.correlation,"
+ "s.most_common_elems,"
+ "s.most_common_elem_freqs,"
+ "s.elem_count_histogram,");
+
+ if (fout->remoteVersion >= 170000)
+ appendPQExpBufferStr(query,
+ "s.range_length_histogram,"
+ "s.range_empty_frac,"
+ "s.range_bounds_histogram ");
+ else
+ appendPQExpBufferStr(query,
+ "NULL AS range_length_histogram,"
+ "NULL AS range_empty_frac,"
+ "NULL AS range_bounds_histogram ");
+
+ appendPQExpBufferStr(query,
+ "FROM pg_stats s "
+ "JOIN pg_namespace n "
+ "ON n.nspname = s.schemaname "
+ "JOIN pg_class c "
+ "ON c.relname = s.tablename "
+ "AND c.relnamespace = n.oid "
+ "WHERE s.schemaname = ");
+ appendStringLiteralAH(query, schemaname, fout);
+ appendPQExpBufferStr(query, " AND s.tablename = ");
+ appendStringLiteralAH(query, relname, fout);
+ appendPQExpBufferStr(query, " ORDER BY s.attname, s.inherited");
+}
+
+
+/*
+ * appendNamedArgument --
+ *
+ * Convenience routine for constructing parameters of the form:
+ * 'paraname', 'value'::type
+ */
+static void
+appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
+ const char *argval, const char *argtype)
+{
+ appendPQExpBufferStr(out, "\t");
+
+ appendStringLiteralAH(out, argname, fout);
+ appendPQExpBufferStr(out, ", ");
+
+ appendStringLiteralAH(out, argval, fout);
+ appendPQExpBuffer(out, "::%s", argtype);
+}
+
+/*
+ * appendRelStatsImport --
+ *
+ * Append a formatted pg_restore_relation_stats statement.
+ */
+static void
+appendRelStatsImport(PQExpBuffer out, Archive *fout, PGresult *res)
+{
+ const char *sep = "";
+
+ if (PQntuples(res) == 0)
+ return;
+
+ appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
+
+ for (int argno = 0; argno < lengthof(rel_stats_arginfo); argno++)
+ {
+ const char *argname = rel_stats_arginfo[argno][0];
+ const char *argtype = rel_stats_arginfo[argno][1];
+ int fieldno = PQfnumber(res, argname);
+
+ if (fieldno < 0)
+ pg_fatal("relation stats export query missing field '%s'",
+ argname);
+
+ if (PQgetisnull(res, 0, fieldno))
+ continue;
+
+ appendPQExpBufferStr(out, sep);
+ appendNamedArgument(out, fout, argname, PQgetvalue(res, 0, fieldno), argtype);
+
+ sep = ",\n";
+ }
+ appendPQExpBufferStr(out, "\n);\n");
+}
+
+/*
+ * appendAttStatsImport --
+ *
+ * Append a series of formatted pg_restore_attribute_stats statements.
+ */
+static void
+appendAttStatsImport(PQExpBuffer out, Archive *fout, PGresult *res)
+{
+ for (int rownum = 0; rownum < PQntuples(res); rownum++)
+ {
+ const char *sep = "";
+
+ appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
+ 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");
+ }
+}
+
+/*
+ * dumpRelationStats --
+ *
+ * Dump command to import stats into the relation on the new database.
+ */
+static void
+dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
+{
+ PGresult *res;
+ PQExpBuffer query;
+ PQExpBuffer out;
+ PQExpBuffer tag;
+ DumpableObject *dobj = (DumpableObject *) &rsinfo->dobj;
+
+ /* nothing to do if we are not dumping statistics */
+ if (!fout->dopt->dumpStatistics)
+ return;
+
+ tag = createPQExpBuffer();
+ appendPQExpBuffer(tag, "%s %s", "STATISTICS DATA", fmtId(dobj->name));
+
+ query = createPQExpBuffer();
+ out = createPQExpBuffer();
+
+ getRelStatsExportQuery(query, fout, dobj->namespace->dobj.name,
+ dobj->name);
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ appendRelStatsImport(out, fout, res);
+ PQclear(res);
+
+ getAttStatsExportQuery(query, fout, dobj->namespace->dobj.name,
+ dobj->name);
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ appendAttStatsImport(out, fout, res);
+ PQclear(res);
+
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ ARCHIVE_OPTS(.tag = tag->data,
+ .namespace = dobj->namespace->dobj.name,
+ .description = "STATISTICS DATA",
+ .section = SECTION_POST_DATA,
+ .owner = rsinfo->stat_relation->rolname,
+ .createStmt = out->data,
+ .deps = dobj->dependencies,
+ .nDeps = dobj->nDeps));
+
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(out);
+ destroyPQExpBuffer(tag);
+}
+
/*
* dumpTableComment --
*
@@ -10744,6 +11113,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_SUBSCRIPTION_REL:
dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
break;
+ case DO_REL_STATS:
+ dumpRelationStats(fout, (const RelStatsInfo *) dobj);
+ break;
case DO_PRE_DATA_BOUNDARY:
case DO_POST_DATA_BOUNDARY:
/* never dumped, nothing to do */
@@ -18949,6 +19321,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
case DO_PUBLICATION_TABLE_IN_SCHEMA:
case DO_SUBSCRIPTION:
case DO_SUBSCRIPTION_REL:
+ case DO_REL_STATS:
/* Post-data objects: must come after the post-data boundary */
addObjectDependency(dobj, postDataBound->dumpId);
break;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index f62b564ed1b..09d4970ecd2 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -84,6 +84,7 @@ typedef enum
DO_PUBLICATION_TABLE_IN_SCHEMA,
DO_SUBSCRIPTION,
DO_SUBSCRIPTION_REL, /* see note for SubRelInfo */
+ DO_REL_STATS,
} DumpableObjectType;
/*
@@ -429,6 +430,12 @@ typedef struct _indexAttachInfo
IndxInfo *partitionIdx; /* link to index on partition */
} IndexAttachInfo;
+typedef struct _relStatsInfo
+{
+ DumpableObject dobj;
+ TableInfo *stat_relation; /* link to relation the stat is for */
+} RelStatsInfo;
+
typedef struct _statsExtInfo
{
DumpableObject dobj;
@@ -763,6 +770,7 @@ extern InhInfo *getInherits(Archive *fout, int *numInherits);
extern void getPartitioningInfo(Archive *fout);
extern void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getExtendedStatistics(Archive *fout);
+extern void getRelationStatistics(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getRules(Archive *fout);
extern void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index dc9a28924bd..76f02db5e04 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -97,7 +97,8 @@ enum dbObjectTypePriorities
PRIO_SUBSCRIPTION_REL,
PRIO_DEFAULT_ACL, /* done in ACL pass */
PRIO_EVENT_TRIGGER, /* must be next to last! */
- PRIO_REFRESH_MATVIEW /* must be last! */
+ PRIO_REFRESH_MATVIEW, /* must be last! */
+ PRIO_RELSTAT, /* must really be last! */
};
/* This table is indexed by enum DumpableObjectType */
@@ -144,6 +145,7 @@ static const int dbObjectTypePriority[] =
[DO_POST_DATA_BOUNDARY] = PRIO_POST_DATA_BOUNDARY,
[DO_EVENT_TRIGGER] = PRIO_EVENT_TRIGGER,
[DO_REFRESH_MATVIEW] = PRIO_REFRESH_MATVIEW,
+ [DO_REL_STATS] = PRIO_RELSTAT,
[DO_POLICY] = PRIO_POLICY,
[DO_PUBLICATION] = PRIO_PUBLICATION,
[DO_PUBLICATION_REL] = PRIO_PUBLICATION_REL,
@@ -152,7 +154,7 @@ static const int dbObjectTypePriority[] =
[DO_SUBSCRIPTION_REL] = PRIO_SUBSCRIPTION_REL,
};
-StaticAssertDecl(lengthof(dbObjectTypePriority) == (DO_SUBSCRIPTION_REL + 1),
+StaticAssertDecl(lengthof(dbObjectTypePriority) == (DO_REL_STATS + 1),
"array length mismatch");
static DumpId preDataBoundId;
@@ -1500,6 +1502,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"POST-DATA BOUNDARY (ID %d)",
obj->dumpId);
return;
+ case DO_REL_STATS:
+ snprintf(buf, bufsize,
+ "RELATION STATISTICS FOR %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
}
/* shouldn't get here */
snprintf(buf, bufsize,
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 396f79781c5..7effb704905 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -103,6 +103,7 @@ static int use_setsessauth = 0;
static int no_comments = 0;
static int no_publications = 0;
static int no_security_labels = 0;
+static int no_statistics = 0;
static int no_subscriptions = 0;
static int no_toast_compression = 0;
static int no_unlogged_table_data = 0;
@@ -172,6 +173,7 @@ main(int argc, char *argv[])
{"no-role-passwords", no_argument, &no_role_passwords, 1},
{"no-security-labels", no_argument, &no_security_labels, 1},
{"no-subscriptions", no_argument, &no_subscriptions, 1},
+ {"no-statistics", no_argument, &no_statistics, 1},
{"no-sync", no_argument, NULL, 4},
{"no-toast-compression", no_argument, &no_toast_compression, 1},
{"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
@@ -451,6 +453,8 @@ main(int argc, char *argv[])
appendPQExpBufferStr(pgdumpopts, " --no-publications");
if (no_security_labels)
appendPQExpBufferStr(pgdumpopts, " --no-security-labels");
+ if (no_statistics)
+ appendPQExpBufferStr(pgdumpopts, " --no-statistics");
if (no_subscriptions)
appendPQExpBufferStr(pgdumpopts, " --no-subscriptions");
if (no_toast_compression)
@@ -666,6 +670,7 @@ help(void)
printf(_(" --no-publications do not dump publications\n"));
printf(_(" --no-role-passwords do not dump passwords for roles\n"));
printf(_(" --no-security-labels do not dump security label assignments\n"));
+ printf(_(" --no-statistics do not dump statistics\n"));
printf(_(" --no-subscriptions do not dump subscriptions\n"));
printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
printf(_(" --no-table-access-method do not dump table access methods\n"));
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 88ae39d938a..2cc7d3eeb08 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -63,6 +63,9 @@ main(int argc, char **argv)
int numWorkers = 1;
Archive *AH;
char *inputFileSpec;
+ bool data_only = false;
+ bool schema_only = false;
+ bool statistics_only = false;
static int disable_triggers = 0;
static int enable_row_security = 0;
static int if_exists = 0;
@@ -71,12 +74,13 @@ main(int argc, char **argv)
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
static int no_comments = 0;
+ static int no_data = 0;
static int no_publications = 0;
+ static int no_schema = 0;
static int no_security_labels = 0;
+ static int no_statistics = 0;
static int no_subscriptions = 0;
static int strict_names = 0;
- bool data_only = false;
- bool schema_only = false;
struct option cmdopts[] = {
{"clean", 0, NULL, 'c'},
@@ -108,6 +112,7 @@ main(int argc, char **argv)
{"username", 1, NULL, 'U'},
{"verbose", 0, NULL, 'v'},
{"single-transaction", 0, NULL, '1'},
+ {"statistics-only", no_argument, NULL, 'X'},
/*
* the following options don't have an equivalent short option letter
@@ -124,9 +129,12 @@ main(int argc, char **argv)
{"transaction-size", required_argument, NULL, 5},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-comments", no_argument, &no_comments, 1},
+ {"no-data", no_argument, &no_data, 1},
{"no-publications", no_argument, &no_publications, 1},
+ {"no-schema", no_argument, &no_schema, 1},
{"no-security-labels", no_argument, &no_security_labels, 1},
{"no-subscriptions", no_argument, &no_subscriptions, 1},
+ {"no-statistics", no_argument, &no_statistics, 1},
{"filter", required_argument, NULL, 4},
{NULL, 0, NULL, 0}
@@ -271,6 +279,10 @@ main(int argc, char **argv)
opts->aclsSkip = 1;
break;
+ case 'X': /* Restore statistics only */
+ statistics_only = true;
+ break;
+
case '1': /* Restore data in a single transaction */
opts->single_txn = true;
opts->exit_on_error = true;
@@ -343,6 +355,10 @@ main(int argc, char **argv)
if (data_only && schema_only)
pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
+ if (data_only && statistics_only)
+ pg_fatal("options -a/--data-only and -X/--statistics-only cannot be used together");
+ if (schema_only && statistics_only)
+ pg_fatal("options -s/--schema-only and -X/--statistics-only cannot be used together");
if (data_only && opts->dropSchema)
pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
@@ -362,8 +378,17 @@ main(int argc, char **argv)
pg_fatal("cannot specify both --single-transaction and multiple jobs");
/* set derivative flags */
- opts->dumpSchema = (!data_only);
- opts->dumpData = (!schema_only);
+ opts->dumpData = data_only || (!schema_only && !statistics_only);
+ opts->dumpSchema = schema_only || (!data_only && !statistics_only);
+ opts->dumpStatistics = statistics_only || (!data_only && !schema_only);
+
+ if (no_data)
+ opts->dumpData = false;
+ if (no_schema)
+ opts->dumpSchema = false;
+ if (no_statistics ||
+ (opts->dumpSections && (!(opts->dumpSections & DUMP_POST_DATA))))
+ opts->dumpStatistics = false;
opts->disable_triggers = disable_triggers;
opts->enable_row_security = enable_row_security;
@@ -484,6 +509,7 @@ usage(const char *progname)
printf(_(" -t, --table=NAME restore named relation (table, view, etc.)\n"));
printf(_(" -T, --trigger=NAME restore named trigger\n"));
printf(_(" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n"));
+ printf(_(" -X, --statistics-only restore only the statistics, not schema or data\n"));
printf(_(" -1, --single-transaction restore as a single transaction\n"));
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
printf(_(" --enable-row-security enable row security\n"));
@@ -491,10 +517,14 @@ usage(const char *progname)
" in FILENAME\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
printf(_(" --no-comments do not restore comment commands\n"));
+ printf(_(" --no-data do not restore data\n"));
printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n"
" created\n"));
printf(_(" --no-publications do not restore publications\n"));
+ printf(_(" --no-schema do not restore schema\n"));
printf(_(" --no-security-labels do not restore security labels\n"));
+ printf(_(" --no-statistics do not restore statistics\n"));
+ /* This hack is only needed in a data-only restore */
printf(_(" --no-subscriptions do not restore subscriptions\n"));
printf(_(" --no-table-access-method do not restore table access methods\n"));
printf(_(" --no-tablespaces do not restore tablespace assignments\n"));
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
index 214240f1ae5..f29da06ed28 100644
--- a/src/bin/pg_dump/t/001_basic.pl
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -50,12 +50,30 @@ command_fails_like(
'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together'
);
+command_fails_like(
+ [ 'pg_dump', '-s', '-X' ],
+ qr/\Qpg_dump: error: options -s\/--schema-only and -X\/--statistics-only cannot be used together\E/,
+ 'pg_dump: error: options -s/--schema-only and -X/--statistics-only cannot be used together'
+);
+
+command_fails_like(
+ [ 'pg_dump', '-a', '-X' ],
+ qr/\Qpg_dump: error: options -a\/--data-only and -X\/--statistics-only cannot be used together\E/,
+ 'pg_dump: error: options -a/--data-only and -X/--statistics-only cannot be used together'
+);
+
command_fails_like(
[ 'pg_dump', '-s', '--include-foreign-data=xxx' ],
qr/\Qpg_dump: error: options -s\/--schema-only and --include-foreign-data cannot be used together\E/,
'pg_dump: options -s/--schema-only and --include-foreign-data cannot be used together'
);
+command_fails_like(
+ [ 'pg_dump', '--statistics-only', '--no-statistics' ],
+ qr/\Qpg_dump: error: options -X\/--statistics-only and --no-statistics cannot be used together\E/,
+ 'pg_dump: options -X\/--statistics-only and --no-statistics cannot be used together'
+);
+
command_fails_like(
[ 'pg_dump', '-j2', '--include-foreign-data=xxx' ],
qr/\Qpg_dump: error: option --include-foreign-data is not supported with parallel backup\E/,
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index bf65d44b942..da8b6e85f3e 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -66,7 +66,7 @@ my %pgdump_runs = (
'--format=custom',
"--file=$tempdir/binary_upgrade.dump",
'-w',
- '--schema-only',
+ '--no-data',
'--binary-upgrade',
'-d', 'postgres', # alternative way to specify database
],
@@ -645,7 +645,19 @@ my %pgdump_runs = (
'--schema=dump_test', '-b', '-B', '--no-sync', 'postgres',
],
- },);
+ },
+ no_statistics => {
+ dump_cmd => [
+ 'pg_dump', "--file=$tempdir/no_statistics.sql",
+ '--no-sync', '--no-statistics', 'postgres',
+ ],
+ },
+ no_schema => {
+ dump_cmd => [
+ 'pg_dump', "--file=$tempdir/no_schema.sql",
+ '--no-sync', '--no-schema', 'postgres',
+ ],
+ });
###############################################################
# Definition of the tests to run.
@@ -711,6 +723,7 @@ my %full_runs = (
no_large_objects => 1,
no_owner => 1,
no_privs => 1,
+ no_statistics => 1,
no_table_access_method => 1,
pg_dumpall_dbprivs => 1,
pg_dumpall_exclude => 1,
@@ -912,6 +925,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
},
@@ -1325,6 +1339,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
},
@@ -1346,6 +1361,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
},
@@ -1367,6 +1383,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
},
@@ -1533,6 +1550,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
},
@@ -1686,6 +1704,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
only_dump_test_table => 1,
section_data => 1,
},
@@ -1713,6 +1732,7 @@ my %tests = (
data_only => 1,
exclude_test_table => 1,
exclude_test_table_data => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -1733,7 +1753,10 @@ my %tests = (
\QCOPY dump_test.fk_reference_test_table (col1) FROM stdin;\E
\n(?:\d\n){5}\\\.\n
/xms,
- like => { data_only => 1, },
+ like => {
+ data_only => 1,
+ no_schema => 1,
+ },
},
'COPY test_second_table' => {
@@ -1749,6 +1772,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -1771,6 +1795,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -1794,6 +1819,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -1816,6 +1842,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -1838,6 +1865,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
},
unlike => {
@@ -3234,6 +3262,7 @@ my %tests = (
like => {
%full_runs,
data_only => 1,
+ no_schema => 1,
section_data => 1,
only_dump_test_schema => 1,
test_schema_plus_large_objects => 1,
@@ -3404,6 +3433,7 @@ my %tests = (
%full_runs,
%dump_test_schema_runs,
data_only => 1,
+ no_schema => 1,
only_dump_measurement => 1,
section_data => 1,
only_dump_test_schema => 1,
@@ -4286,6 +4316,7 @@ my %tests = (
column_inserts => 1,
data_only => 1,
inserts => 1,
+ no_schema => 1,
section_data => 1,
test_schema_plus_large_objects => 1,
binary_upgrade => 1,
@@ -4586,6 +4617,31 @@ my %tests = (
},
},
+ #
+ # Table statistics should go in section=data.
+ # Materialized view statistics should go in section=post-data.
+ #
+ 'statistics_import' => {
+ create_sql => '
+ CREATE TABLE dump_test.has_stats
+ AS SELECT g.g AS x, g.g / 2 AS y FROM generate_series(1,100) AS g(g);
+ CREATE TABLE dump_test.has_stats_mv AS SELECT * FROM dump_test.has_stats;
+ ANALYZE dump_test.has_stats, dump_test.has_stats_mv;',
+ regexp => qr/pg_catalog.pg_restore_attribute_stats/,
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_post_data => 1,
+ no_schema => 1,
+ },
+ unlike => {
+ exclude_dump_test_schema => 1,
+ no_statistics => 1,
+ only_dump_measurement => 1,
+ schema_only => 1,
+ },
+ },
+
# CREATE TABLE with partitioned table and various AMs. One
# partition uses the same default as the parent, and a second
# uses its own AM.
diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c
index 8ce0fa3020e..a29cd2cca98 100644
--- a/src/bin/pg_upgrade/dump.c
+++ b/src/bin/pg_upgrade/dump.c
@@ -21,10 +21,11 @@ generate_old_dump(void)
/* run new pg_dumpall binary for globals */
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
- "\"%s/pg_dumpall\" %s --globals-only --quote-all-identifiers "
+ "\"%s/pg_dumpall\" %s %s --globals-only --quote-all-identifiers "
"--binary-upgrade %s --no-sync -f \"%s/%s\"",
new_cluster.bindir, cluster_conn_opts(&old_cluster),
log_opts.verbose ? "--verbose" : "",
+ user_opts.do_statistics ? "" : "--no-statistics",
log_opts.dumpdir,
GLOBALS_DUMP_FILE);
check_ok();
@@ -52,10 +53,11 @@ generate_old_dump(void)
snprintf(log_file_name, sizeof(log_file_name), DB_DUMP_LOG_FILE_MASK, old_db->db_oid);
parallel_exec_prog(log_file_name, NULL,
- "\"%s/pg_dump\" %s --schema-only --quote-all-identifiers "
+ "\"%s/pg_dump\" %s --no-data %s --quote-all-identifiers "
"--binary-upgrade --format=custom %s --no-sync --file=\"%s/%s\" %s",
new_cluster.bindir, cluster_conn_opts(&old_cluster),
log_opts.verbose ? "--verbose" : "",
+ user_opts.do_statistics ? "" : "--no-statistics",
log_opts.dumpdir,
sql_file_name, escaped_connstr.data);
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 108eb7a1ba4..3b6c7ec994e 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -60,6 +60,8 @@ parseCommandLine(int argc, char *argv[])
{"copy", no_argument, NULL, 2},
{"copy-file-range", no_argument, NULL, 3},
{"sync-method", required_argument, NULL, 4},
+ {"with-statistics", no_argument, NULL, 5},
+ {"no-statistics", no_argument, NULL, 6},
{NULL, 0, NULL, 0}
};
@@ -70,6 +72,7 @@ parseCommandLine(int argc, char *argv[])
user_opts.do_sync = true;
user_opts.transfer_mode = TRANSFER_MODE_COPY;
+ user_opts.do_statistics = true;
os_info.progname = get_progname(argv[0]);
@@ -212,6 +215,13 @@ parseCommandLine(int argc, char *argv[])
user_opts.sync_method = pg_strdup(optarg);
break;
+ case 5:
+ user_opts.do_statistics = true;
+ break;
+ case 6:
+ user_opts.do_statistics = false;
+ break;
+
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
os_info.progname);
@@ -306,7 +316,9 @@ usage(void)
printf(_(" --clone clone instead of copying files to new cluster\n"));
printf(_(" --copy copy files to new cluster (default)\n"));
printf(_(" --copy-file-range copy files to new cluster with copy_file_range\n"));
+ printf(_(" --no-statistics do not import statistics from old cluster\n"));
printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
+ printf(_(" --with-statistics import statistics from old cluster (default)\n"));
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\n"
"Before running pg_upgrade you must:\n"
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 0cdd675e4f1..3fe111fbde5 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -327,6 +327,7 @@ typedef struct
int jobs; /* number of processes/threads to use */
char *socketdir; /* directory to use for Unix sockets */
char *sync_method;
+ bool do_statistics; /* carry over statistics from old cluster */
} UserOpts;
typedef struct
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 668bddbfcd7..8a0968aaa7b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2398,6 +2398,7 @@ RelMapFile
RelMapping
RelOptInfo
RelOptKind
+RelStatsInfo
RelToCheck
RelToCluster
RelabelType
--
2.34.1