Support --include-analyze in pg_dump, pg_dumpall, pg_restore
hi.
after watching https://www.youtube.com/live/k4A9-WZET_4?si=vz3lTud735s2vcCO
then trying to hack it too.
the implemented feature is as the $subject description, making pg_dump
also includes the ANALYZE command in its output.
if option --include-analyze not specified, then pg_dump will not dump
ANALYZE, that's the status quo.
option --include-analyze support table relkind: RELKIND_PARTITIONED_TABLE,
RELKIND_MATVIEW, RELKIND_RELATION.
this option cannot be used with option --schema-only.
for materialized view, it will dump after the refresh materialized
view command.
(tested in several cases, ANALYZE will really be at the end of the dump).
By default, pg_restore does not restore the ANALYZE commands.
This means that if the archive contains ANALYZE commands,
you still need to explicitly specify the --include-analyze option to
restore them.
doc added.
demo for dump:
create materialized view mvw as select a from generate_series(1, 3) a;
---<<<<<<<<<<<<<<portion of pg_dump output starts>>>>>>>>>>>>>>>>>>>>>>
--
-- Name: mvw; Type: MATERIALIZED VIEW DATA; Schema: public; Owner: jian
--
REFRESH MATERIALIZED VIEW public.mvw;
--
-- Name: mvw; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.mvw;
---<<<<<<<<<<<<<<portion of pg_dump output ends>>>>>>>>>>>>>>>>>>>>>>
demo for dump partitioned table:
CREATE TABLE prt1 (a int, b int, c text) PARTITION BY RANGE(a) ;
CREATE TABLE prt1_p1 PARTITION OF prt1 FOR VALUES FROM (0) TO (5);
CREATE TABLE prt1_p2 PARTITION OF prt1 FOR VALUES FROM (8) TO (11);
INSERT INTO prt1 SELECT i, i+11, to_char(i, 'FM0000') FROM
generate_series(0, 2) i;
pg_dump --table=*prt1* --include-analyze
---<<<<<<<<<<<<<<portion of output ends>>>>>>>>>>>>>>>>>>>>>>
--
-- Data for Name: prt1_p1; Type: TABLE DATA; Schema: public; Owner: jian
--
COPY public.prt1_p1 (a, b, c) FROM stdin;
0 11 0000
1 12 0001
2 13 0002
\.
--
-- Data for Name: prt1_p2; Type: TABLE DATA; Schema: public; Owner: jian
--
COPY public.prt1_p2 (a, b, c) FROM stdin;
\.
--
-- Name: prt1; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE ONLY public.prt1;
--
-- Name: prt1_p1; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.prt1_p1;
--
-- Name: prt1_p2; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.prt1_p2;
---<<<<<<<<<<<<<<portion of output starts>>>>>>>>>>>>>>>>>>>>>>
TODO item: writing tests.
idea credits to Andrey Borodin, Nikolay Samokhvalov, Kirk Wolak
what do you think?
Attachments:
v1-0001-Support-include-analyze-in-pg_dump-pg_dumpall-pg_.patchtext/x-patch; charset=US-ASCII; name=v1-0001-Support-include-analyze-in-pg_dump-pg_dumpall-pg_.patchDownload
From c2ca01f95428dce498618c1a87fda62b3e2467dd Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Tue, 14 Jan 2025 16:39:31 +0800
Subject: [PATCH v1 1/1] Support --include-analyze in pg_dump, pg_dumpall,
pg_restore
The default is false. Maybe it should be true.
support table relkind: RELKIND_PARTITIONED_TABLE,
RELKIND_MATVIEW, RELKIND_RELATION.
it cannot be used with option --schema-only.
for materialized view, it will dump after refresh materialized view command
By default, pg_restore does not restore the ANALYZE commands.
This means that if the archive contains ANALYZE commands,
you still need need explicitly specify the --include-analyze option to restore them.
doc added.
demo for dump:
create materialized view mvw as select a from generate_series(1, 3) a;
---<<<<<<<<<<<<<<portion of output starts>>>>>>>>>>>>>>>>>>>>>>
--
-- Name: mvw; Type: MATERIALIZED VIEW DATA; Schema: public; Owner: jian
--
REFRESH MATERIALIZED VIEW public.mvw;
--
-- Name: mvw; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.mvw;
---<<<<<<<<<<<<<<portion of output ends>>>>>>>>>>>>>>>>>>>>>>
demo for dump partitioned table:
CREATE TABLE prt1 (a int, b int, c text) PARTITION BY RANGE(a) ;
CREATE TABLE prt1_p1 PARTITION OF prt1 FOR VALUES FROM (0) TO (5);
CREATE TABLE prt1_p2 PARTITION OF prt1 FOR VALUES FROM (8) TO (11);
INSERT INTO prt1 SELECT i, i+11, to_char(i, 'FM0000') FROM generate_series(0, 2) i;
pg_dump --table=*prt1* --include-analyze
---<<<<<<<<<<<<<<portion of output ends>>>>>>>>>>>>>>>>>>>>>>
--
-- Data for Name: prt1_p1; Type: TABLE DATA; Schema: public; Owner: jian
--
COPY public.prt1_p1 (a, b, c) FROM stdin;
0 11 0000
1 12 0001
2 13 0002
\.
--
-- Data for Name: prt1_p2; Type: TABLE DATA; Schema: public; Owner: jian
--
COPY public.prt1_p2 (a, b, c) FROM stdin;
\.
--
-- Name: prt1; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE ONLY public.prt1;
--
-- Name: prt1_p1; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.prt1_p1;
--
-- Name: prt1_p2; Type: ANALYZE; Schema: public; Owner: jian
--
ANALYZE public.prt1_p2;
---<<<<<<<<<<<<<<portion of output starts>>>>>>>>>>>>>>>>>>>>>>
TODO writing tests.
discussion: https://postgr.es/m/
---
doc/src/sgml/ref/pg_dump.sgml | 10 +++
doc/src/sgml/ref/pg_dumpall.sgml | 10 +++
doc/src/sgml/ref/pg_restore.sgml | 13 +++
src/bin/pg_dump/common.c | 3 +
src/bin/pg_dump/pg_backup.h | 2 +
src/bin/pg_dump/pg_backup_archiver.c | 7 +-
src/bin/pg_dump/pg_dump.c | 113 +++++++++++++++++++++++++++
src/bin/pg_dump/pg_dump.h | 13 +++
src/bin/pg_dump/pg_dump_sort.c | 9 ++-
src/bin/pg_dump/pg_dumpall.c | 5 ++
src/bin/pg_dump/pg_restore.c | 7 ++
src/bin/pg_dump/t/001_basic.pl | 12 +++
src/tools/pgindent/typedefs.list | 1 +
13 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index d66e901f51..6f0bbdec20 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -982,6 +982,16 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--include-analyze</option></term>
+ <listitem>
+ <para>
+ Do dump <command>ANALYZE</command> commands.
+ This option only applys to regular table, materialized view or partitioned table.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--include-foreign-data=<replaceable class="parameter">foreignserver</replaceable></option></term>
<listitem>
diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml
index 014f279258..a540fae5d3 100644
--- a/doc/src/sgml/ref/pg_dumpall.sgml
+++ b/doc/src/sgml/ref/pg_dumpall.sgml
@@ -367,6 +367,16 @@ exclude database <replaceable class="parameter">PATTERN</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--include-analyze</option></term>
+ <listitem>
+ <para>
+ Do dump <command>ANALYZE</command> commands.
+ This option only applys to regular table, materialized view or partitioned table.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--inserts</option></term>
<listitem>
diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml
index b8b27e1719..a745400f63 100644
--- a/doc/src/sgml/ref/pg_restore.sgml
+++ b/doc/src/sgml/ref/pg_restore.sgml
@@ -671,6 +671,17 @@ PostgreSQL documentation
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--include-analyze</option></term>
+ <listitem>
+ <para>
+ Do output <command>ANALYZE</command> commands for analyzing tables if the archive contains them.
+ If <application>pg_dump</application> specified <option>--include-analyze</option> option,
+ the archive may contain <command>ANALYZE</command> commands.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--no-comments</option></term>
<listitem>
@@ -1044,6 +1055,8 @@ CREATE DATABASE foo WITH TEMPLATE template0;
restored table so the optimizer has useful statistics; see
<xref linkend="vacuum-for-statistics"/> and
<xref linkend="autovacuum"/> for more information.
+ You can achieve the same effect by including the <option>--include-analyze</option> option
+ when running <application>pg_restore</application>.
</para>
</refsect1>
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 56b6c368ac..c44ac4993f 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -228,6 +228,9 @@ getSchemaData(Archive *fout, int *numTablesPtr)
pg_log_info("reading rewrite rules");
getRules(fout);
+ pg_log_info("reading analyze info");
+ getAnalyzes(fout, tblinfo, numTables);
+
pg_log_info("reading policies");
getPolicies(fout, tblinfo, numTables);
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index f0f19bb0b2..dfb5b4c121 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -109,6 +109,7 @@ typedef struct _restoreOptions
int dump_inserts; /* 0 = COPY, otherwise rows per INSERT */
int column_inserts;
int if_exists;
+ int include_analyze;
int no_comments; /* Skip comments */
int no_publications; /* Skip publication entries */
int no_security_labels; /* Skip security label entries */
@@ -178,6 +179,7 @@ typedef struct _dumpOptions
int disable_dollar_quoting;
int column_inserts;
int if_exists;
+ int include_analyze;
int no_comments;
int no_security_labels;
int no_publications;
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 707a3fc844..365bd78551 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -170,6 +170,7 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
dopt->dumpData = ropt->dumpData;
dopt->dumpSchema = ropt->dumpSchema;
dopt->if_exists = ropt->if_exists;
+ dopt->include_analyze = ropt->include_analyze;
dopt->column_inserts = ropt->column_inserts;
dopt->dumpSections = ropt->dumpSections;
dopt->aclsSkip = ropt->aclsSkip;
@@ -2940,6 +2941,9 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
if (ropt->aclsSkip && _tocEntryIsACL(te))
return 0;
+ if (!ropt->include_analyze && strcmp(te->desc, "ANALYZE") == 0)
+ return 0;
+
/* If it's a comment, maybe ignore it */
if (ropt->no_comments && strcmp(te->desc, "COMMENT") == 0)
return 0;
@@ -3196,7 +3200,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, "ANALYZE") == 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 8f73a5df95..7bd48c37cc 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -359,6 +359,7 @@ static void getLOs(Archive *fout);
static void dumpLO(Archive *fout, const LoInfo *loinfo);
static int dumpLOs(Archive *fout, const void *arg);
static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
+static void dumpAnalyze(Archive *fout, const AnalyzeInfo *analyzeinfo);
static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
@@ -479,6 +480,7 @@ main(int argc, char **argv)
{"exclude-table-data", required_argument, NULL, 4},
{"extra-float-digits", required_argument, NULL, 8},
{"if-exists", no_argument, &dopt.if_exists, 1},
+ {"include-analyze", no_argument, &dopt.include_analyze, 1},
{"inserts", no_argument, NULL, 9},
{"lock-wait-timeout", required_argument, NULL, 2},
{"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
@@ -788,6 +790,9 @@ main(int argc, char **argv)
if (schema_only && foreign_servers_include_patterns.head != NULL)
pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
+ if (schema_only && dopt.include_analyze)
+ pg_fatal("options -s/--schema-only and --include-analyze cannot be used together");
+
if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
pg_fatal("option --include-foreign-data is not supported with parallel backup");
@@ -1100,6 +1105,7 @@ main(int argc, char **argv)
ropt->dumpData = dopt.dumpData;
ropt->dumpSchema = dopt.dumpSchema;
ropt->if_exists = dopt.if_exists;
+ ropt->include_analyze = dopt.include_analyze;
ropt->column_inserts = dopt.column_inserts;
ropt->dumpSections = dopt.dumpSections;
ropt->aclsSkip = dopt.aclsSkip;
@@ -1213,6 +1219,7 @@ help(const char *progname)
printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
" based on expressions in FILENAME\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
+ printf(_(" --include-analyze do dump analyze commands\n"));
printf(_(" --include-foreign-data=PATTERN\n"
" include data of foreign tables on foreign\n"
" servers matching PATTERN\n"));
@@ -4151,6 +4158,68 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
destroyPQExpBuffer(tbloids);
}
+/*
+ * getAnalyzes
+ * get information about tables (regular table, partitioned table, materialized
+ * view) to be analyzed.
+ */
+void
+getAnalyzes(Archive *fout, TableInfo tblinfo[], int numTables)
+{
+ int i = 0;
+ int ntbl = 0;
+ AnalyzeInfo *analyze_info = NULL;
+ TableInfo *tbinfo = NULL;
+ Oid *tabldids = NULL;
+
+ if(!fout->dopt->include_analyze ||
+ fout->remoteVersion < 180000)
+ return;
+
+ tabldids = pg_malloc0(numTables * sizeof(Oid));
+ for (i = 0; i < numTables; i++)
+ {
+ tbinfo = &tblinfo[i];
+
+ /* It can't have RLS or policies if it's not a table */
+ if (!(tbinfo->relkind == RELKIND_RELATION ||
+ tbinfo->relkind == RELKIND_MATVIEW ||
+ tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
+ continue;
+
+ if (tbinfo->relpersistence != RELPERSISTENCE_PERMANENT)
+ continue;
+
+ if (!tbinfo->dobj.dump)
+ continue;
+
+ if (!tbinfo->interesting)
+ continue;
+
+ tabldids[ntbl] = tbinfo->dobj.catId.oid;
+ ntbl++;
+ }
+
+ if(ntbl >0)
+ {
+ analyze_info = pg_malloc(ntbl * sizeof(AnalyzeInfo));
+
+ for (i = 0; i < ntbl; i++)
+ {
+ tbinfo = findTableByOid(tabldids[i]);
+ analyze_info[i].dobj.objType = DO_ANALYZE;
+ analyze_info[i].dobj.catId.tableoid = 0;
+ analyze_info[i].dobj.catId.oid = tbinfo->dobj.catId.oid;
+ AssignDumpId(&analyze_info[i].dobj);
+ analyze_info[i].dobj.catId.tableoid = RelationRelationId;
+ analyze_info[i].dobj.namespace = tbinfo->dobj.namespace;
+ analyze_info[i].dobj.name = pg_strdup(tbinfo->dobj.name);
+ analyze_info[i].analyzetable = tbinfo;
+ }
+ }
+ free(tabldids);
+}
+
/*
* dumpPolicy
* dump the definition of the given policy
@@ -4269,6 +4338,45 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
free(qtabname);
}
+/*
+ * dumpAnalyze
+ * dump the definition of the ANALYZE command for appliable table.
+ */
+static void
+dumpAnalyze(Archive *fout, const AnalyzeInfo *analyzeinfo)
+{
+ PQExpBuffer q;
+ TableInfo * tbinfo = NULL;
+ DumpOptions *dopt = fout->dopt;
+
+ /* Do nothing if not include_analyze specified */
+ if (!dopt->include_analyze)
+ return;
+ Assert(dopt->dumpData);
+
+ tbinfo = (TableInfo *) analyzeinfo->analyzetable;
+ q = createPQExpBuffer();
+ if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
+ appendPQExpBuffer(q, "ANALYZE ONLY %s;",
+ fmtQualifiedDumpable(tbinfo));
+ else
+ {
+ appendPQExpBuffer(q, "ANALYZE %s;",
+ fmtQualifiedDumpable(tbinfo));
+ Assert(tbinfo->relkind == RELKIND_MATVIEW || tbinfo->relkind == RELKIND_RELATION);
+ }
+
+ ArchiveEntry(fout, analyzeinfo->dobj.catId, analyzeinfo->dobj.dumpId,
+ ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+ .namespace = analyzeinfo->dobj.namespace->dobj.name,
+ .relkind = tbinfo->relkind,
+ .owner = tbinfo->rolname,
+ .description = "ANALYZE",
+ .section = SECTION_POST_DATA,
+ .createStmt = q->data));
+ destroyPQExpBuffer(q);
+}
+
/*
* getPublications
* get information about publications
@@ -10635,6 +10743,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_REFRESH_MATVIEW:
refreshMatViewData(fout, (const TableDataInfo *) dobj);
break;
+ case DO_ANALYZE:
+ dumpAnalyze(fout, (const AnalyzeInfo *) dobj);
+ break;
case DO_RULE:
dumpRule(fout, (const RuleInfo *) dobj);
break;
@@ -16888,6 +16999,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
free(qualrelname);
}
+
/*
* dumpTableAttach
* write to fout the commands to attach a child partition
@@ -18940,6 +19052,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
case DO_INDEX_ATTACH:
case DO_STATSEXT:
case DO_REFRESH_MATVIEW:
+ case DO_ANALYZE:
case DO_TRIGGER:
case DO_EVENT_TRIGGER:
case DO_DEFAULT_ACL:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index f62b564ed1..4573039bd4 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -78,6 +78,7 @@ typedef enum
DO_POST_DATA_BOUNDARY,
DO_EVENT_TRIGGER,
DO_REFRESH_MATVIEW,
+ DO_ANALYZE,
DO_POLICY,
DO_PUBLICATION,
DO_PUBLICATION_REL,
@@ -625,6 +626,17 @@ typedef struct _policyInfo
char *polwithcheck;
} PolicyInfo;
+
+/*
+ * The AnalyzeInfo struct is used to represent ANALYZE command on a table and to
+ * indicate if a table need ANALYZE
+ */
+typedef struct _analyzeInfo
+{
+ DumpableObject dobj;
+ TableInfo *analyzetable;
+} AnalyzeInfo;
+
/*
* The PublicationInfo struct is used to represent publications.
*/
@@ -784,6 +796,7 @@ extern void processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
int numExtensions);
extern void getEventTriggers(Archive *fout);
extern void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables);
+extern void getAnalyzes(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getPublications(Archive *fout);
extern void getPublicationNamespaces(Archive *fout);
extern void getPublicationTables(Archive *fout, TableInfo tblinfo[],
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index dc9a28924b..5b78e72a45 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_ANALYZE, /* 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_ANALYZE] = PRIO_ANALYZE,
[DO_POLICY] = PRIO_POLICY,
[DO_PUBLICATION] = PRIO_PUBLICATION,
[DO_PUBLICATION_REL] = PRIO_PUBLICATION_REL,
@@ -1356,6 +1358,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
+ case DO_ANALYZE:
+ snprintf(buf, bufsize,
+ "ANALYZE %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
case DO_RULE:
snprintf(buf, bufsize,
"RULE %s (ID %d OID %u)",
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 396f79781c..976b5b47ad 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -96,6 +96,7 @@ static int column_inserts = 0;
static int disable_dollar_quoting = 0;
static int disable_triggers = 0;
static int if_exists = 0;
+static int include_analyze = 0;
static int inserts = 0;
static int no_table_access_method = 0;
static int no_tablespaces = 0;
@@ -159,6 +160,7 @@ main(int argc, char *argv[])
{"exclude-database", required_argument, NULL, 6},
{"extra-float-digits", required_argument, NULL, 5},
{"if-exists", no_argument, &if_exists, 1},
+ {"include-analyze", no_argument, &include_analyze, 1},
{"inserts", no_argument, &inserts, 1},
{"lock-wait-timeout", required_argument, NULL, 2},
{"no-table-access-method", no_argument, &no_table_access_method, 1},
@@ -435,6 +437,8 @@ main(int argc, char *argv[])
appendPQExpBufferStr(pgdumpopts, " --disable-triggers");
if (inserts)
appendPQExpBufferStr(pgdumpopts, " --inserts");
+ if (include_analyze)
+ appendPQExpBufferStr(pgdumpopts, " --include-analyze");
if (no_table_access_method)
appendPQExpBufferStr(pgdumpopts, " --no-table-access-method");
if (no_tablespaces)
@@ -660,6 +664,7 @@ help(void)
printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
printf(_(" --filter=FILENAME exclude databases based on expressions in FILENAME\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
+ printf(_(" --include-analyze do dump analyze commands\n"));
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"));
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 88ae39d938..25dfa1a800 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -70,6 +70,7 @@ main(int argc, char **argv)
static int outputNoTableAm = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ static int include_analyze = 0;
static int no_comments = 0;
static int no_publications = 0;
static int no_security_labels = 0;
@@ -115,6 +116,7 @@ main(int argc, char **argv)
{"disable-triggers", no_argument, &disable_triggers, 1},
{"enable-row-security", no_argument, &enable_row_security, 1},
{"if-exists", no_argument, &if_exists, 1},
+ {"include-analyze", no_argument, &include_analyze, 1},
{"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
{"no-table-access-method", no_argument, &outputNoTableAm, 1},
{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
@@ -361,6 +363,9 @@ main(int argc, char **argv)
if (opts->single_txn && numWorkers > 1)
pg_fatal("cannot specify both --single-transaction and multiple jobs");
+ if (schema_only && include_analyze)
+ pg_fatal("options -s/--schema-only and --include-analyze cannot be used together");
+
/* set derivative flags */
opts->dumpSchema = (!data_only);
opts->dumpData = (!schema_only);
@@ -379,6 +384,7 @@ main(int argc, char **argv)
if (if_exists && !opts->dropSchema)
pg_fatal("option --if-exists requires option -c/--clean");
opts->if_exists = if_exists;
+ opts->include_analyze = include_analyze;
opts->strict_names = strict_names;
if (opts->formatName)
@@ -490,6 +496,7 @@ usage(const char *progname)
printf(_(" --filter=FILENAME restore or skip objects based on expressions\n"
" in FILENAME\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
+ printf(_(" --include-analyze do restore analyze commands\n"));
printf(_(" --no-comments do not restore comment commands\n"));
printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n"
" created\n"));
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
index 214240f1ae..c3ad062c2d 100644
--- a/src/bin/pg_dump/t/001_basic.pl
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -50,6 +50,12 @@ command_fails_like(
'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together'
);
+command_fails_like(
+ [ 'pg_dump', '-s', '--include-analyze' ],
+ qr/\Qpg_dump: error: options -s\/--schema-only and --include-analyze cannot be used together\E/,
+ 'pg_dump: error: options -s/--schema-only and --include-analyze 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/,
@@ -62,6 +68,12 @@ command_fails_like(
'pg_dump: option --include-foreign-data is not supported with parallel backup'
);
+command_fails_like(
+ [ 'pg_restore', '-s', '-f -', '--include-analyze' ],
+ qr/\Qg_restore: error: options -s\/--schema-only and --include-analyze cannot be used together\E/,
+ 'pg_restore: error: options -s/--schema-only and --include-analyze cannot be used together'
+);
+
command_fails_like(
['pg_restore'],
qr{\Qpg_restore: error: one of -d/--dbname and -f/--file must be specified\E},
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index eb93debe10..d25aa15eaa 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2,6 +2,7 @@ ACCESS_ALLOWED_ACE
ACL
ACL_SIZE_INFORMATION
AFFIX
+AnalyzeInfo
ASN1_INTEGER
ASN1_OBJECT
ASN1_OCTET_STRING
--
2.34.1
jian he <jian.universality@gmail.com> writes:
the implemented feature is as the $subject description, making pg_dump
also includes the ANALYZE command in its output.
Isn't this pretty much obsoleted by the ongoing work to dump and
restore statistics?
regards, tom lane
On Tue, Jan 14, 2025 at 09:32:19AM -0500, Tom Lane wrote:
jian he <jian.universality@gmail.com> writes:
the implemented feature is as the $subject description, making pg_dump
also includes the ANALYZE command in its output.Isn't this pretty much obsoleted by the ongoing work to dump and
restore statistics?
Yeah, and I believe that work is still on track for v18. That's likely
going to be much faster than analyzing everything, and it'll be usable in
pg_upgrade, too.
/messages/by-id/flat/CADkLM=cB0rF3p_FuWRTMSV0983ihTRpsH+OCpNyiqE7Wk0vUWA@mail.gmail.com
--
nathan