</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-e <replaceable class="parameter">pattern</replaceable></option></term>
+ <term><option>--extension=<replaceable class="parameter">pattern</replaceable></option></term>
+ <listitem>
+ <para>
+ Dump only extensions matching <replaceable
+ class="parameter">pattern</replaceable>. When this option is not
+ specified, all non-system extensions in the target database will be
+ dumped. Multiple extensions can be selected by writing multiple
+ <option>-e</option> switches. The <replaceable
+ class="parameter">pattern</replaceable> parameter is interpreted as a
+ pattern according to the same rules used by
+ <application>psql</application>'s <literal>\d</literal> commands (see
+ <xref linkend="app-psql-patterns"/>), so multiple extensions can also
+ be selected by writing wildcard characters in the pattern. When using
+ wildcards, be careful to quote the pattern if needed to prevent the
+ shell from expanding the wildcards.
+ </para>
+
+ <note>
+ <para>
+ When <option>-e</option> is specified,
+ <application>pg_dump</application> makes no attempt to dump any other
+ database objects that the selected extension(s) might depend upon.
+ Therefore, there is no guarantee that the results of a
+ specific-extension dump can be successfully restored by themselves
+ into a clean database.
+ </para>
+ </note>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-E <replaceable class="parameter">encoding</replaceable></option></term>
<term><option>--encoding=<replaceable class="parameter">encoding</replaceable></option></term>
<term><option>--strict-names</option></term>
<listitem>
<para>
- Require that each schema
- (<option>-n</option>/<option>--schema</option>) and table
- (<option>-t</option>/<option>--table</option>) qualifier match at
- least one schema/table in the database to be dumped. Note that if
- none of the schema/table qualifiers find
+ 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
+ match at least one extension/schema/table in the database to be dumped.
+ Note that if none of the extension/schema/table qualifiers find
matches, <application>pg_dump</application> will generate an error
even without <option>--strict-names</option>.
</para>
static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
+static SimpleStringList extension_include_patterns = {NULL, NULL};
+static SimpleOidList extension_include_oids = {NULL, NULL};
+
static const CatalogId nilCatalogId = {0, 0};
/* override for standard extra_float_digits setting */
SimpleStringList *patterns,
SimpleOidList *oids,
bool strict_names);
+static void expand_extension_name_patterns(Archive *fout,
+ SimpleStringList *patterns,
+ SimpleOidList *oids,
+ bool strict_names);
static void expand_foreign_server_name_patterns(Archive *fout,
SimpleStringList *patterns,
SimpleOidList *oids);
{"clean", no_argument, NULL, 'c'},
{"create", no_argument, NULL, 'C'},
{"dbname", required_argument, NULL, 'd'},
+ {"extension", required_argument, NULL, 'e'},
{"file", required_argument, NULL, 'f'},
{"format", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
InitDumpOptions(&dopt);
- while ((c = getopt_long(argc, argv, "abBcCd: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:RsS:t:T:U:vwWxZ:",
long_options, &optindex)) != -1)
{
switch (c)
dopt.cparams.dbname = pg_strdup(optarg);
break;
+ case 'e': /* include extension(s) */
+ simple_string_list_append(&extension_include_patterns, optarg);
+ dopt.include_everything = false;
+ break;
+
case 'E': /* Dump encoding */
dumpencoding = pg_strdup(optarg);
break;
/* non-matching exclusion patterns aren't an error */
+ /* Expand extension selection patterns into OID lists */
+ if (extension_include_patterns.head != NULL)
+ {
+ expand_extension_name_patterns(fout, &extension_include_patterns,
+ &extension_include_oids,
+ strict_names);
+ if (extension_include_oids.head == NULL)
+ fatal("no matching extensions were found");
+ }
+
/*
* Dumping blobs is the default for dumps where an inclusion switch is not
* used (an "include everything" dump). -B can be used to exclude blobs
printf(_(" -B, --no-blobs exclude large objects in dump\n"));
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(_(" -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"));
destroyPQExpBuffer(query);
}
+/*
+ * Find the OIDs of all extensions matching the given list of patterns,
+ * and append them to the given OID list.
+ */
+static void
+expand_extension_name_patterns(Archive *fout,
+ SimpleStringList *patterns,
+ SimpleOidList *oids,
+ bool strict_names)
+{
+ PQExpBuffer query;
+ PGresult *res;
+ SimpleStringListCell *cell;
+ int i;
+
+ if (patterns->head == NULL)
+ return; /* nothing to do */
+
+ query = createPQExpBuffer();
+
+ /*
+ * The loop below runs multiple SELECTs might sometimes result in
+ * duplicate entries in the OID list, but we don't care.
+ */
+ for (cell = patterns->head; cell; cell = cell->next)
+ {
+ appendPQExpBufferStr(query,
+ "SELECT oid FROM pg_catalog.pg_extension e\n");
+ processSQLNamePattern(GetConnection(fout), query, cell->val, false,
+ false, NULL, "e.extname", NULL, NULL);
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ if (strict_names && PQntuples(res) == 0)
+ fatal("no matching extensions were found for pattern \"%s\"", cell->val);
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
+ }
+
+ PQclear(res);
+ resetPQExpBuffer(query);
+ }
+
+ destroyPQExpBuffer(query);
+}
+
/*
* Find the OIDs of all foreign servers matching the given list of patterns,
* and append them to the given OID list.
* Built-in extensions should be skipped except for checking ACLs, since we
* assume those will already be installed in the target database. We identify
* such extensions by their having OIDs in the range reserved for initdb.
- * We dump all user-added extensions by default, or none of them if
- * include_everything is false (i.e., a --schema or --table switch was given).
+ * We dump all user-added extensions by default. No extensions are dumped
+ * if include_everything is false (i.e., a --schema or --table switch was
+ * given), except if --extension specifies a list of extensions to dump.
*/
static void
selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
else
- extinfo->dobj.dump = extinfo->dobj.dump_contains =
- dopt->include_everything ? DUMP_COMPONENT_ALL :
- DUMP_COMPONENT_NONE;
+ {
+ /* check if there is a list of extensions to dump */
+ if (extension_include_oids.head != NULL)
+ extinfo->dobj.dump = extinfo->dobj.dump_contains =
+ simple_oid_list_member(&extension_include_oids,
+ extinfo->dobj.catId.oid) ?
+ DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+ else
+ extinfo->dobj.dump = extinfo->dobj.dump_contains =
+ dopt->include_everything ?
+ DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+ }
}
/*
'pg_dump', '--no-sync', "--file=$tempdir/section_post_data.sql",
'--section=post-data', 'postgres',
],
+ },
+ with_extension => {
+ dump_cmd => [
+ 'pg_dump', '--no-sync', "--file=$tempdir/with_extension.sql",
+ '--extension=test_pg_dump', '--no-sync', 'postgres',
+ ],
+ },
+
+ # plgsql in the list blocks the dump of extension test_pg_dump
+ without_extension => {
+ dump_cmd => [
+ 'pg_dump', '--no-sync', "--file=$tempdir/without_extension.sql",
+ '--extension=plpgsql', '--no-sync', 'postgres',
+ ],
},);
###############################################################
# Tests which are considered 'full' dumps by pg_dump, but there
# are flags used to exclude specific items (ACLs, blobs, etc).
my %full_runs = (
- binary_upgrade => 1,
- clean => 1,
- clean_if_exists => 1,
- createdb => 1,
- defaults => 1,
- exclude_table => 1,
- no_privs => 1,
- no_owner => 1,);
+ binary_upgrade => 1,
+ clean => 1,
+ clean_if_exists => 1,
+ createdb => 1,
+ defaults => 1,
+ exclude_table => 1,
+ no_privs => 1,
+ no_owner => 1,
+ with_extension => 1,
+ without_extension => 1);
my %tests = (
'ALTER EXTENSION test_pg_dump' => {
schema_only => 1,
section_pre_data => 1,
},
- unlike => { binary_upgrade => 1, },
+ unlike => { binary_upgrade => 1, without_extension => 1 },
},
'CREATE ROLE regress_dump_test_role' => {
section_data => 1,
extension_schema => 1,
},
+ unlike => { without_extension => 1, },
},
'CREATE TABLE regress_pg_dump_table' => {
extension_schema => 1,
},
unlike => {
- binary_upgrade => 1,
- exclude_table => 1,
+ binary_upgrade => 1,
+ exclude_table => 1,
+ without_extension => 1,
},
},
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1, },
},
'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE wgo_then_regular' => {
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1, },
},
'CREATE ACCESS METHOD regress_test_am' => {
schema_only => 1,
section_pre_data => 1,
},
+ unlike => { without_extension => 1, },
},
'GRANT SELECT regress_pg_dump_table_added pre-ALTER EXTENSION' => {
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1, },
},
'GRANT SELECT ON TABLE regress_pg_dump_table' => {
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1 },
},
'GRANT USAGE ON regress_pg_dump_table_col1_seq TO regress_dump_test_role'
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1, },
},
'GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role' => {
schema_only => 1,
section_pre_data => 1,
},
- unlike => { no_privs => 1, },
+ unlike => { no_privs => 1, without_extension => 1, },
},
# Objects included in extension part of a schema created by this extension */