Allow pg_dump to include/exclude child tables automatically.

This patch adds new pg_dump switches
    --table-and-children=pattern
    --exclude-table-and-children=pattern
    --exclude-table-data-and-children=pattern
which act the same as the existing --table, --exclude-table, and
--exclude-table-data switches, except that any partitions or
inheritance child tables of the table(s) matching the pattern
are also included or excluded.

Gilles Darold, reviewed by Stéphane Tachoires

Discussion: https://postgr.es/m/5aa393b5-5f67-8447-b83e-544516990ee2@migops.com
This commit is contained in:
Tom Lane 2023-03-14 16:09:03 -04:00
parent 684ffac8c7
commit a563c24c95
3 changed files with 571 additions and 96 deletions

View File

@ -775,6 +775,19 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--exclude-table-and-children=<replaceable class="parameter">pattern</replaceable></option></term>
<listitem>
<para>
This is the same as
the <option>-T</option>/<option>--exclude-table</option> option,
except that it also excludes any partitions or inheritance child
tables of the table(s) matching the
<replaceable class="parameter">pattern</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--exclude-table-data=<replaceable class="parameter">pattern</replaceable></option></term>
<listitem>
@ -793,6 +806,18 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--exclude-table-data-and-children=<replaceable class="parameter">pattern</replaceable></option></term>
<listitem>
<para>
This is the same as the <option>--exclude-table-data</option> option,
except that it also excludes data of any partitions or inheritance
child tables of the table(s) matching the
<replaceable class="parameter">pattern</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--extra-float-digits=<replaceable class="parameter">ndigits</replaceable></option></term>
<listitem>
@ -1142,9 +1167,9 @@ PostgreSQL documentation
Require that each
extension (<option>-e</option>/<option>--extension</option>),
schema (<option>-n</option>/<option>--schema</option>) and
table (<option>-t</option>/<option>--table</option>) qualifier
table (<option>-t</option>/<option>--table</option>) pattern
match at least one extension/schema/table in the database to be dumped.
Note that if none of the extension/schema/table qualifiers find
Note that if none of the extension/schema/table patterns find
matches, <application>pg_dump</application> will generate an error
even without <option>--strict-names</option>.
</para>
@ -1158,6 +1183,19 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--table-and-children=<replaceable class="parameter">pattern</replaceable></option></term>
<listitem>
<para>
This is the same as
the <option>-t</option>/<option>--table</option> option,
except that it also includes any partitions or inheritance child
tables of the table(s) matching the
<replaceable class="parameter">pattern</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--use-set-session-authorization</option></term>
<listitem>

View File

@ -119,11 +119,15 @@ static SimpleStringList schema_exclude_patterns = {NULL, NULL};
static SimpleOidList schema_exclude_oids = {NULL, NULL};
static SimpleStringList table_include_patterns = {NULL, NULL};
static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
static SimpleOidList table_include_oids = {NULL, NULL};
static SimpleStringList table_exclude_patterns = {NULL, NULL};
static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
static SimpleOidList table_exclude_oids = {NULL, NULL};
static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
@ -180,7 +184,8 @@ static void expand_foreign_server_name_patterns(Archive *fout,
static void expand_table_name_patterns(Archive *fout,
SimpleStringList *patterns,
SimpleOidList *oids,
bool strict_names);
bool strict_names,
bool with_child_tables);
static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
const char *pattern);
@ -421,6 +426,9 @@ 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},
{"table-and-children", required_argument, NULL, 12},
{"exclude-table-and-children", required_argument, NULL, 13},
{"exclude-table-data-and-children", required_argument, NULL, 14},
{NULL, 0, NULL, 0}
};
@ -631,6 +639,22 @@ main(int argc, char **argv)
optarg);
break;
case 12: /* include table(s) and their children */
simple_string_list_append(&table_include_patterns_and_children,
optarg);
dopt.include_everything = false;
break;
case 13: /* exclude table(s) and their children */
simple_string_list_append(&table_exclude_patterns_and_children,
optarg);
break;
case 14: /* exclude data of table(s) and children */
simple_string_list_append(&tabledata_exclude_patterns_and_children,
optarg);
break;
default:
/* getopt_long already emitted a complaint */
pg_log_error_hint("Try \"%s --help\" for more information.", progname);
@ -810,21 +834,30 @@ main(int argc, char **argv)
/* non-matching exclusion patterns aren't an error */
/* Expand table selection patterns into OID lists */
if (table_include_patterns.head != NULL)
{
expand_table_name_patterns(fout, &table_include_patterns,
&table_include_oids,
strict_names);
if (table_include_oids.head == NULL)
pg_fatal("no matching tables were found");
}
expand_table_name_patterns(fout, &table_include_patterns,
&table_include_oids,
strict_names, false);
expand_table_name_patterns(fout, &table_include_patterns_and_children,
&table_include_oids,
strict_names, true);
if ((table_include_patterns.head != NULL ||
table_include_patterns_and_children.head != NULL) &&
table_include_oids.head == NULL)
pg_fatal("no matching tables were found");
expand_table_name_patterns(fout, &table_exclude_patterns,
&table_exclude_oids,
false);
false, false);
expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
&table_exclude_oids,
false, true);
expand_table_name_patterns(fout, &tabledata_exclude_patterns,
&tabledata_exclude_oids,
false);
false, false);
expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
&tabledata_exclude_oids,
false, true);
expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
&foreign_servers_include_oids);
@ -1051,7 +1084,7 @@ help(const char *progname)
" plain-text format\n"));
printf(_(" -s, --schema-only dump only the schema, no data\n"));
printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
printf(_(" -t, --table=PATTERN dump the specified table(s) only\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(_(" --binary-upgrade for use by upgrade utilities only\n"));
@ -1060,7 +1093,13 @@ help(const char *progname)
printf(_(" --disable-triggers disable triggers during data-only restore\n"));
printf(_(" --enable-row-security enable row security (dump only content user has\n"
" access to)\n"));
printf(_(" --exclude-table-and-children=PATTERN\n"
" do NOT dump the specified table(s),\n"
" including child and partition tables\n"));
printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
printf(_(" --exclude-table-data-and-children=PATTERN\n"
" do NOT dump data for the specified table(s),\n"
" including child and partition tables\n"));
printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
printf(_(" --include-foreign-data=PATTERN\n"
@ -1084,6 +1123,8 @@ help(const char *progname)
printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
printf(_(" --strict-names require table and/or schema include patterns to\n"
" match at least one entity each\n"));
printf(_(" --table-and-children=PATTERN dump only the specified table(s),\n"
" including child and partition tables\n"));
printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n"));
@ -1497,7 +1538,7 @@ expand_foreign_server_name_patterns(Archive *fout,
static void
expand_table_name_patterns(Archive *fout,
SimpleStringList *patterns, SimpleOidList *oids,
bool strict_names)
bool strict_names, bool with_child_tables)
{
PQExpBuffer query;
PGresult *res;
@ -1523,7 +1564,15 @@ expand_table_name_patterns(Archive *fout,
* Query must remain ABSOLUTELY devoid of unqualified names. This
* would be unnecessary given a pg_table_is_visible() variant taking a
* search_path argument.
*
* For with_child_tables, we start with the basic query's results and
* recursively search the inheritance tree to add child tables.
*/
if (with_child_tables)
{
appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
}
appendPQExpBuffer(query,
"SELECT c.oid"
"\nFROM pg_catalog.pg_class c"
@ -1546,6 +1595,17 @@ expand_table_name_patterns(Archive *fout,
prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
termPQExpBuffer(&dbbuf);
if (with_child_tables)
{
appendPQExpBuffer(query, "UNION"
"\nSELECT i.inhrelid"
"\nFROM partition_tree p"
"\n JOIN pg_catalog.pg_inherits i"
"\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
"\n)"
"\nSELECT relid FROM partition_tree");
}
ExecuteSqlStatement(fout, "RESET search_path");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
PQclear(ExecuteSqlQueryForSingleRow(fout,

File diff suppressed because it is too large Load Diff