diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index 2c938cd7e1494..dd943a19d5189 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -1172,6 +1172,17 @@ PostgreSQL documentation
+
+
+
+
+ Include or exclude from a dump all child and partition tables when a parent
+ table is specified using option /
+ or /.
+
+
+
+
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index aba780ef4b1ee..09284c82be3f4 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -200,6 +200,7 @@ typedef struct _dumpOptions
int sequence_data; /* dump sequence data even in schema-only mode */
int do_nothing;
+ bool with_childs;
} DumpOptions;
/*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 44d957c038895..7463b73bbe0d6 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -421,6 +421,7 @@ main(int argc, char **argv)
{"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
{"rows-per-insert", required_argument, NULL, 10},
{"include-foreign-data", required_argument, NULL, 11},
+ {"with-childs", no_argument, NULL, 12},
{NULL, 0, NULL, 0}
};
@@ -631,6 +632,10 @@ main(int argc, char **argv)
optarg);
break;
+ case 12: /* dump child table too */
+ dopt.with_childs = true;
+ break;
+
default:
/* getopt_long already emitted a complaint */
pg_log_error_hint("Try \"%s --help\" for more information.", progname);
@@ -810,6 +815,14 @@ main(int argc, char **argv)
false);
/* non-matching exclusion patterns aren't an error */
+ /*
+ * The include child option require that there is
+ * at least one table inclusion
+ */
+ if (dopt.with_childs && table_include_patterns.head == NULL
+ && table_exclude_patterns.head == NULL)
+ pg_fatal("option --with-childs requires option -t/--table or -T/--exclude-table");
+
/* Expand table selection patterns into OID lists */
if (table_include_patterns.head != NULL)
{
@@ -1088,6 +1101,9 @@ help(const char *progname)
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
+ printf(_(" --with-childs include or exclude from a dump all child and partition\n"
+ " tables when a parent table is specified using\n"
+ " -t/--table or -T/--exclude-table\n"));
printf(_("\nConnection options:\n"));
printf(_(" -d, --dbname=DBNAME database to dump\n"));
@@ -1520,6 +1536,15 @@ expand_table_name_patterns(Archive *fout,
PQExpBufferData dbbuf;
int dotcnt;
+ /*
+ * With --include_child we look recursively to the inheritance
+ * tree to find the childs tables of the matching include filter
+ */
+ if (fout->dopt->with_childs)
+ {
+ appendPQExpBuffer(query, "WITH RECURSIVE child_tree (relid) AS (\n");
+ }
+
/*
* Query must remain ABSOLUTELY devoid of unqualified names. This
* would be unnecessary given a pg_table_is_visible() variant taking a
@@ -1547,6 +1572,20 @@ expand_table_name_patterns(Archive *fout,
prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
termPQExpBuffer(&dbbuf);
+ if (fout->dopt->with_childs)
+ {
+ appendPQExpBuffer(query, "\n UNION ALL"
+ "\n SELECT c.oid AS relid"
+ "\n FROM child_tree AS p"
+ "\n JOIN pg_catalog.pg_inherits AS i"
+ "\n ON (p.relid OPERATOR(pg_catalog.=) i.inhparent)"
+ "\n JOIN pg_catalog.pg_class AS c"
+ "\n ON (c.oid OPERATOR(pg_catalog.=) i.inhrelid)"
+ "\n)"
+ "\nSELECT relid FROM child_tree");
+
+ }
+
ExecuteSqlStatement(fout, "RESET search_path");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
PQclear(ExecuteSqlQueryForSingleRow(fout,
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 7c3067a3f4ba6..2f95b7a6e0e34 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -319,6 +319,17 @@
'--exclude-table=dump_test.test_table', 'postgres',
],
},
+ exclude_child_table => {
+ dump_cmd => [
+ 'pg_dump',
+ '--no-sync',
+ '--with-childs',
+ "--file=$tempdir/exclude_child_table.sql",
+ '--exclude-table=dump_test.measurement',
+ 'postgres',
+ ],
+ },
+
exclude_test_table_data => {
dump_cmd => [
'pg_dump',
@@ -413,6 +424,18 @@
'postgres',
],
},
+ include_child_table => {
+ dump_cmd => [
+ 'pg_dump',
+ '--no-sync',
+ '--with-childs',
+ "--file=$tempdir/include_child_table.sql",
+ '--table=dump_test.measurement',
+ '--lock-wait-timeout='
+ . (1000 * $PostgreSQL::Test::Utils::timeout_default),
+ 'postgres',
+ ],
+ },
role => {
dump_cmd => [
'pg_dump',
@@ -541,6 +564,7 @@
compression => 1,
createdb => 1,
defaults => 1,
+ exclude_child_table => 1,
exclude_dump_test_schema => 1,
exclude_test_table => 1,
exclude_test_table_data => 1,
@@ -936,6 +960,10 @@
role => 1,
section_pre_data => 1,
binary_upgrade => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -1025,11 +1053,16 @@
'ALTER TABLE measurement OWNER TO' => {
regexp => qr/^\QALTER TABLE dump_test.measurement OWNER TO \E.+;/m,
- like =>
- { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_pre_data => 1,
+ include_child_table => 1,
+ },
unlike => {
exclude_dump_test_schema => 1,
no_owner => 1,
+ exclude_child_table => 1,
},
},
@@ -1040,8 +1073,12 @@
%full_runs,
role => 1,
section_pre_data => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ no_owner => 1,
+ exclude_child_table => 1,
},
- unlike => { no_owner => 1, },
},
'ALTER FOREIGN TABLE foreign_table OWNER TO' => {
@@ -2793,11 +2830,16 @@
\)\n
\QPARTITION BY RANGE (logdate);\E\n
/xm,
- like =>
- { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_pre_data => 1,
+ include_child_table => 1,
+ },
unlike => {
binary_upgrade => 1,
exclude_dump_test_schema => 1,
+ exclude_child_table => 1,
},
},
@@ -2824,6 +2866,10 @@
section_pre_data => 1,
role => 1,
binary_upgrade => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -2838,10 +2884,14 @@
\QEXECUTE FUNCTION dump_test.trigger_func();\E
/xm,
like => {
- %full_runs, %dump_test_schema_runs, section_post_data => 1,
+ %full_runs,
+ %dump_test_schema_runs,
+ section_post_data => 1,
+ include_child_table => 1,
},
unlike => {
exclude_dump_test_schema => 1,
+ exclude_child_table => 1,
},
},
@@ -2869,6 +2919,10 @@
section_post_data => 1,
role => 1,
binary_upgrade => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -2881,6 +2935,10 @@
section_post_data => 1,
role => 1,
binary_upgrade => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -2893,6 +2951,10 @@
section_post_data => 1,
role => 1,
binary_upgrade => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -3250,6 +3312,7 @@
schema_only => 1,
section_post_data => 1,
test_schema_plus_large_objects => 1,
+ include_child_table => 1,
},
unlike => {
exclude_dump_test_schema => 1,
@@ -3258,6 +3321,7 @@
pg_dumpall_globals_clean => 1,
role => 1,
section_pre_data => 1,
+ exclude_child_table => 1,
},
},
@@ -3271,9 +3335,16 @@
\QALTER TABLE ONLY dump_test.measurement\E \n^\s+
\QADD CONSTRAINT measurement_pkey PRIMARY KEY (city_id, logdate);\E
/xm,
- like =>
- { %full_runs, %dump_test_schema_runs, section_post_data => 1, },
- unlike => { exclude_dump_test_schema => 1, },
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_post_data => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_dump_test_schema => 1,
+ exclude_child_table => 1,
+ },
},
'CREATE INDEX ... ON measurement_y2006_m2' => {
@@ -3284,6 +3355,10 @@
%full_runs,
role => 1,
section_post_data => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -3295,6 +3370,10 @@
%full_runs,
role => 1,
section_post_data => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ exclude_child_table => 1,
},
},
@@ -3324,6 +3403,7 @@
role => 1,
schema_only => 1,
section_post_data => 1,
+ include_child_table => 1,
},
unlike => {
only_dump_test_schema => 1,
@@ -3332,6 +3412,7 @@
pg_dumpall_globals_clean => 1,
section_pre_data => 1,
test_schema_plus_large_objects => 1,
+ exclude_child_table => 1,
},
},
@@ -3614,11 +3695,16 @@
TO regress_dump_test_role;',
regexp =>
qr/^\QGRANT SELECT ON TABLE dump_test.measurement TO regress_dump_test_role;\E/m,
- like =>
- { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_pre_data => 1,
+ include_child_table => 1,
+ },
unlike => {
exclude_dump_test_schema => 1,
no_privs => 1,
+ exclude_child_table => 1,
},
},
@@ -3636,8 +3722,12 @@
%full_runs,
role => 1,
section_pre_data => 1,
+ include_child_table => 1,
+ },
+ unlike => {
+ no_privs => 1,
+ exclude_child_table => 1,
},
- unlike => { no_privs => 1, },
},
'GRANT ALL ON LARGE OBJECT ...' => {
@@ -3884,6 +3974,7 @@
only_dump_test_table => 1,
role => 1,
section_pre_data => 1,
+ include_child_table => 1,
},
unlike => { no_privs => 1, },
},
@@ -4106,6 +4197,13 @@
qr/pg_dumpall: error: improper qualified name \(too many dotted names\): myhost\.mydb/,
'pg_dumpall: option --exclude-database rejects multipart database names');
+#########################################
+# Test invalid use of --with-childs
+$node->command_fails_like(
+ [ 'pg_dump', '-p', "$port", '--with-childs' ],
+ qr/pg_dump: error: option --with-childs requires option -t\/--table or -T\/--exclude-table/,
+ 'pg_dump: option --with-childs require inclusion or exclusion of tables');
+
#########################################
# Test valid database exclusion patterns