On Sat, 16 Mar 2024 at 17:36, Ayush Vatsa <ayushvatsa1...@gmail.com> wrote: > > Attached is the complete patch with all the required code changes. > Looking forward to your review and feedback. >
This looks good to me. I tested it and everything worked as expected. I ran it through pgindent to fix some whitespace issues and added another test for the filter option, based on the test case you added. I'm marking this ready-for-commit (which I'll probably do myself in a day or two, unless anyone else claims it first). Regards, Dean
From f757ebe748ab47d1e1ab40b343af2a43a9183287 Mon Sep 17 00:00:00 2001 From: Ayush Vatsa <ayuva...@amazon.com> Date: Mon, 25 Dec 2023 14:46:05 +0530 Subject: [PATCH v3] Add support for --exclude-extension in pg_dump When specified, extensions matching the given pattern are excluded in dumps. --- doc/src/sgml/ref/pg_dump.sgml | 34 ++++++-- src/bin/pg_dump/pg_dump.c | 33 +++++++- src/test/modules/test_pg_dump/t/001_base.pl | 88 ++++++++++++++++++--- 3 files changed, 139 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 0caf56e0e0..8edf03a03d 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -256,6 +256,27 @@ PostgreSQL documentation </listitem> </varlistentry> + <varlistentry> + <term><option>--exclude-extension=<replaceable class="parameter">pattern</replaceable></option></term> + <listitem> + <para> + Do not dump any extensions matching <replaceable + class="parameter">pattern</replaceable>. The pattern is + interpreted according to the same rules as for <option>-e</option>. + <option>--exclude-extension</option> can be given more than once to exclude extensions + matching any of several patterns. + </para> + + <para> + When both <option>-e</option> and <option>--exclude-extension</option> are given, the behavior + is to dump just the extensions that match at least one <option>-e</option> + switch but no <option>--exclude-extension</option> switches. If <option>--exclude-extension</option> + appears without <option>-e</option>, then extensions matching <option>--exclude-extension</option> are + excluded from what is otherwise a normal dump. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><option>-E <replaceable class="parameter">encoding</replaceable></option></term> <term><option>--encoding=<replaceable class="parameter">encoding</replaceable></option></term> @@ -848,10 +869,11 @@ PostgreSQL documentation <option>--exclude-table-and-children</option> or <option>-T</option> for tables, <option>-n</option>/<option>--schema</option> for schemas, - <option>--include-foreign-data</option> for data on foreign servers and + <option>--include-foreign-data</option> for data on foreign servers, <option>--exclude-table-data</option>, - <option>--exclude-table-data-and-children</option> for table data, - <option>-e</option>/<option>--extension</option> for extensions. + <option>--exclude-table-data-and-children</option> for table data, and + <option>-e</option>/<option>--extension</option> or + <option>--exclude-extension</option> for extensions. To read from <literal>STDIN</literal>, use <filename>-</filename> as the filename. The <option>--filter</option> option can be specified in conjunction with the above listed options for including or excluding @@ -874,8 +896,7 @@ PostgreSQL documentation <listitem> <para> <literal>extension</literal>: extensions, works like the - <option>--extension</option> option. This keyword can only be - used with the <literal>include</literal> keyword. + <option>-e</option>/<option>--extension</option> option. </para> </listitem> <listitem> @@ -1278,7 +1299,8 @@ PostgreSQL documentation </para> <para> This option has no effect - on <option>-N</option>/<option>--exclude-schema</option>, + on <option>--exclude-extension</option>, + <option>-N</option>/<option>--exclude-schema</option>, <option>-T</option>/<option>--exclude-table</option>, or <option>--exclude-table-data</option>. An exclude pattern failing to match any objects is not considered an error. diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a5149ca823..3ab7c6676a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -136,6 +136,9 @@ static SimpleOidList foreign_servers_include_oids = {NULL, NULL}; static SimpleStringList extension_include_patterns = {NULL, NULL}; static SimpleOidList extension_include_oids = {NULL, NULL}; +static SimpleStringList extension_exclude_patterns = {NULL, NULL}; +static SimpleOidList extension_exclude_oids = {NULL, NULL}; + static const CatalogId nilCatalogId = {0, 0}; /* override for standard extra_float_digits setting */ @@ -437,6 +440,7 @@ main(int argc, char **argv) {"exclude-table-data-and-children", required_argument, NULL, 14}, {"sync-method", required_argument, NULL, 15}, {"filter", required_argument, NULL, 16}, + {"exclude-extension", required_argument, NULL, 17}, {NULL, 0, NULL, 0} }; @@ -672,6 +676,11 @@ main(int argc, char **argv) read_dump_filters(optarg, &dopt); break; + case 17: /* exclude extension(s) */ + simple_string_list_append(&extension_exclude_patterns, + optarg); + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -890,6 +899,10 @@ main(int argc, char **argv) if (extension_include_oids.head == NULL) pg_fatal("no matching extensions were found"); } + expand_extension_name_patterns(fout, &extension_exclude_patterns, + &extension_exclude_oids, + false); + /* non-matching exclusion patterns aren't an error */ /* * Dumping LOs is the default for dumps where an inclusion switch is not @@ -1095,6 +1108,7 @@ help(const char *progname) printf(_(" -c, --clean clean (drop) database objects before recreating\n")); printf(_(" -C, --create include commands to create database in dump\n")); printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n")); + printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n")); printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n")); printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n")); printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n")); @@ -2028,6 +2042,12 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt) extinfo->dobj.dump = extinfo->dobj.dump_contains = dopt->include_everything ? DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE; + + /* check that the extension is not explicitly excluded */ + if (extinfo->dobj.dump && + simple_oid_list_member(&extension_exclude_oids, + extinfo->dobj.catId.oid)) + extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE; } } @@ -18265,6 +18285,15 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[], curext->dobj.catId.oid)) continue; + /* + * Check if this extension is listed as to exclude in the dump. If + * yes, any table data associated with it is discarded. + */ + if (extension_exclude_oids.head != NULL && + simple_oid_list_member(&extension_exclude_oids, + curext->dobj.catId.oid)) + continue; + if (strlen(extconfig) != 0 || strlen(extcondition) != 0) { int j; @@ -18965,7 +18994,6 @@ read_dump_filters(const char *filename, DumpOptions *dopt) case FILTER_OBJECT_TYPE_FUNCTION: case FILTER_OBJECT_TYPE_INDEX: case FILTER_OBJECT_TYPE_TRIGGER: - case FILTER_OBJECT_TYPE_EXTENSION: case FILTER_OBJECT_TYPE_FOREIGN_DATA: pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"), "exclude", @@ -18973,6 +19001,9 @@ read_dump_filters(const char *filename, DumpOptions *dopt) exit_nicely(1); break; + case FILTER_OBJECT_TYPE_EXTENSION: + simple_string_list_append(&extension_exclude_patterns, objname); + break; case FILTER_OBJECT_TYPE_TABLE_DATA: simple_string_list_append(&tabledata_exclude_patterns, objname); diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl index b8c30c2387..4266f26c65 100644 --- a/src/test/modules/test_pg_dump/t/001_base.pl +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -220,6 +220,19 @@ my %pgdump_runs = ( '--extension=test_pg_dump', 'postgres', ], }, + exclude_extension => { + dump_cmd => [ + 'pg_dump', '--no-sync', "--file=$tempdir/exclude_extension.sql", + '--exclude-extension=test_pg_dump', 'postgres', + ], + }, + exclude_extension_filter => { + dump_cmd => [ + 'pg_dump', '--no-sync', + "--file=$tempdir/exclude_extension_filter.sql", + "--filter=$tempdir/exclude_extension_filter.txt", 'postgres', + ], + }, # plpgsql in the list blocks the dump of extension test_pg_dump without_extension => { @@ -299,6 +312,8 @@ my %full_runs = ( no_owner => 1, privileged_internals => 1, with_extension => 1, + exclude_extension => 1, + exclude_extension_filter => 1, without_extension => 1); my %tests = ( @@ -325,7 +340,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { binary_upgrade => 1, without_extension => 1 }, + unlike => { + binary_upgrade => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1 + }, }, 'CREATE ROLE regress_dump_test_role' => { @@ -434,7 +454,11 @@ my %tests = ( section_data => 1, extension_schema => 1, }, - unlike => { without_extension => 1, }, + unlike => { + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'CREATE TABLE regress_pg_dump_table' => { @@ -460,6 +484,8 @@ my %tests = ( unlike => { binary_upgrade => 1, exclude_table => 1, + exclude_extension => 1, + exclude_extension_filter => 1, without_extension => 1, }, }, @@ -483,7 +509,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1, }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE wgo_then_regular' => { @@ -500,7 +531,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1, }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'CREATE ACCESS METHOD regress_test_am' => { @@ -520,7 +556,11 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { without_extension => 1, }, + unlike => { + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'GRANT SELECT regress_pg_dump_table_added pre-ALTER EXTENSION' => { @@ -545,7 +585,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1, }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'GRANT SELECT ON TABLE regress_pg_dump_table' => { @@ -579,7 +624,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1 }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1 + }, }, 'GRANT USAGE ON regress_pg_dump_table_col1_seq TO regress_dump_test_role' @@ -595,7 +645,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1, }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, 'GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role' => { @@ -617,7 +672,12 @@ my %tests = ( schema_only => 1, section_pre_data => 1, }, - unlike => { no_privs => 1, without_extension => 1, }, + unlike => { + no_privs => 1, + exclude_extension => 1, + exclude_extension_filter => 1, + without_extension => 1, + }, }, # Objects included in extension part of a schema created by this extension */ @@ -818,6 +878,16 @@ foreach my $test ( # Send the combined set of commands to psql $node->safe_psql('postgres', $create_sql); +######################################### +# Create filter file for exclude_extension_filter test + +my $filterfile; + +open $filterfile, '>', "$tempdir/exclude_extension_filter.txt" + or die "unable to open filter file for writing"; +print $filterfile "exclude extension test_pg_dump\n"; +close $filterfile; + ######################################### # Run all runs -- 2.35.3