diff options
-rw-r--r-- | src/bin/pg_dump/pg_backup_archiver.c | 23 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 74 | ||||
-rw-r--r-- | src/bin/pg_dump/t/002_pg_dump.pl | 92 |
3 files changed, 87 insertions, 102 deletions
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index f55aa36c49c..fb0379377bf 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3453,29 +3453,6 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData) { RestoreOptions *ropt = AH->public.ropt; - /* - * Avoid dumping the public schema, as it will already be created ... - * unless we are using --clean mode (and *not* --create mode), in which - * case we've previously issued a DROP for it so we'd better recreate it. - * - * Likewise for its comment, if any. (We could try issuing the COMMENT - * command anyway; but it'd fail if the restore is done as non-super-user, - * so let's not.) - * - * XXX it looks pretty ugly to hard-wire the public schema like this, but - * it sits in a sort of no-mans-land between being a system object and a - * user object, so it really is special in a way. - */ - if (!(ropt->dropSchema && !ropt->createDB)) - { - if (strcmp(te->desc, "SCHEMA") == 0 && - strcmp(te->tag, "public") == 0) - return; - if (strcmp(te->desc, "COMMENT") == 0 && - strcmp(te->tag, "SCHEMA public") == 0) - return; - } - /* Select owner, schema, and tablespace as necessary */ _becomeOwner(AH, te); _selectOutputSchema(AH, te->namespace); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index d65ea54a69b..b534fb7b95d 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -1407,6 +1407,19 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) /* Other system schemas don't get dumped */ nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE; } + else if (strcmp(nsinfo->dobj.name, "public") == 0) + { + /* + * The public schema is a strange beast that sits in a sort of + * no-mans-land between being a system object and a user object. We + * don't want to dump creation or comment commands for it, because + * that complicates matters for non-superuser use of pg_dump. But we + * should dump any ACL changes that have occurred for it, and of + * course we should dump contained objects. + */ + nsinfo->dobj.dump = DUMP_COMPONENT_ACL; + nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL; + } else nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL; @@ -1617,21 +1630,21 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout) * selectDumpableExtension: policy-setting subroutine * Mark an extension as to be dumped or not * - * Normally, we dump all extensions, or none of them if include_everything - * is false (i.e., a --schema or --table switch was given). However, in - * binary-upgrade mode it's necessary to skip built-in extensions, since we + * 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). */ static void selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt) { /* - * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users to - * change permissions on those objects, if they wish to, and have those - * changes preserved. + * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to + * change permissions on their member objects, if they wish to, and have + * those changes preserved. */ - if (dopt->binary_upgrade && extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid) + 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 = @@ -4435,29 +4448,6 @@ getNamespaces(Archive *fout, int *numNamespaces) init_acl_subquery->data, init_racl_subquery->data); - /* - * When we are doing a 'clean' run, we will be dropping and recreating - * the 'public' schema (the only object which has that kind of - * treatment in the backend and which has an entry in pg_init_privs) - * and therefore we should not consider any initial privileges in - * pg_init_privs in that case. - * - * See pg_backup_archiver.c:_printTocEntry() for the details on why - * the public schema is special in this regard. - * - * Note that if the public schema is dropped and re-created, this is - * essentially a no-op because the new public schema won't have an - * entry in pg_init_privs anyway, as the entry will be removed when - * the public schema is dropped. - * - * Further, we have to handle the case where the public schema does - * not exist at all. - */ - if (dopt->outputClean) - appendPQExpBuffer(query, " AND pip.objoid <> " - "coalesce((select oid from pg_namespace " - "where nspname = 'public'),0)"); - appendPQExpBuffer(query, ") "); destroyPQExpBuffer(acl_subquery); @@ -9945,20 +9935,28 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) if (!dopt->binary_upgrade) { /* - * In a regular dump, we use IF NOT EXISTS so that there isn't a - * problem if the extension already exists in the target database; - * this is essential for installed-by-default extensions such as - * plpgsql. + * In a regular dump, we simply create the extension, intentionally + * not specifying a version, so that the destination installation's + * default version is used. * - * In binary-upgrade mode, that doesn't work well, so instead we skip - * built-in extensions based on their OIDs; see - * selectDumpableExtension. + * Use of IF NOT EXISTS here is unlike our behavior for other object + * types; but there are various scenarios in which it's convenient to + * manually create the desired extension before restoring, so we + * prefer to allow it to exist already. */ appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n", qextname, fmtId(extinfo->namespace)); } else { + /* + * In binary-upgrade mode, it's critical to reproduce the state of the + * database exactly, so our procedure is to create an empty extension, + * restore all the contained objects normally, and add them to the + * extension one by one. This function performs just the first of + * those steps. binary_upgrade_extension_member() takes care of + * adding member objects as they're created. + */ int i; int n; @@ -9968,8 +9966,6 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo) * We unconditionally create the extension, so we must drop it if it * exists. This could happen if the user deleted 'plpgsql' and then * readded it, causing its oid to be greater than g_last_builtin_oid. - * The g_last_builtin_oid test was kept to avoid repeatedly dropping - * and recreating extensions like 'plpgsql'. */ appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 74730bfc659..3e9b4d94dc5 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1548,30 +1548,31 @@ qr/^ALTER (?!EVENT TRIGGER|LARGE OBJECT|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO . all_runs => 1, catch_all => 'COMMENT commands', regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;/m, - like => { + # this shouldn't ever get emitted anymore + like => {}, + unlike => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, no_blobs => 1, - no_privs => 1, no_owner => 1, + no_privs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, + section_post_data => 1, section_pre_data => 1, - with_oids => 1, }, - unlike => { - binary_upgrade => 1, - column_inserts => 1, - data_only => 1, - only_dump_test_schema => 1, - only_dump_test_table => 1, - role => 1, - section_post_data => 1, - test_schema_plus_blobs => 1, }, }, + test_schema_plus_blobs => 1, + with_oids => 1, }, }, 'COMMENT ON TABLE dump_test.test_table' => { all_runs => 1, @@ -2751,33 +2752,34 @@ qr/CREATE CAST \(timestamp with time zone AS interval\) WITH FUNCTION pg_catalog regexp => qr/^ \QCREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\E /xm, - like => { + # this shouldn't ever get emitted anymore + like => {}, + unlike => { + binary_upgrade => 1, clean => 1, clean_if_exists => 1, + column_inserts => 1, createdb => 1, + data_only => 1, defaults => 1, exclude_dump_test_schema => 1, exclude_test_table => 1, exclude_test_table_data => 1, no_blobs => 1, - no_privs => 1, no_owner => 1, - pg_dumpall_dbprivs => 1, - schema_only => 1, - section_pre_data => 1, - with_oids => 1, }, - unlike => { - binary_upgrade => 1, - column_inserts => 1, - data_only => 1, + no_privs => 1, only_dump_test_schema => 1, only_dump_test_table => 1, + pg_dumpall_dbprivs => 1, pg_dumpall_globals => 1, pg_dumpall_globals_clean => 1, role => 1, + schema_only => 1, section_data => 1, section_post_data => 1, - test_schema_plus_blobs => 1, }, }, + section_pre_data => 1, + test_schema_plus_blobs => 1, + with_oids => 1, }, }, 'CREATE AGGREGATE dump_test.newavg' => { all_runs => 1, @@ -4565,11 +4567,12 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog all_runs => 1, catch_all => 'CREATE ... commands', regexp => qr/^CREATE SCHEMA public;/m, - like => { - clean => 1, - clean_if_exists => 1, }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, createdb => 1, defaults => 1, exclude_test_table => 1, @@ -5395,8 +5398,10 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog all_runs => 1, catch_all => 'DROP ... commands', regexp => qr/^DROP SCHEMA public;/m, - like => { clean => 1 }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { + clean => 1, clean_if_exists => 1, pg_dumpall_globals_clean => 1, }, }, @@ -5404,17 +5409,21 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog all_runs => 1, catch_all => 'DROP ... commands', regexp => qr/^DROP SCHEMA IF EXISTS public;/m, - like => { clean_if_exists => 1 }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { clean => 1, + clean_if_exists => 1, pg_dumpall_globals_clean => 1, }, }, 'DROP EXTENSION plpgsql' => { all_runs => 1, catch_all => 'DROP ... commands', regexp => qr/^DROP EXTENSION plpgsql;/m, - like => { clean => 1, }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { + clean => 1, clean_if_exists => 1, pg_dumpall_globals_clean => 1, }, }, @@ -5494,9 +5503,11 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog all_runs => 1, catch_all => 'DROP ... commands', regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;/m, - like => { clean_if_exists => 1, }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { clean => 1, + clean_if_exists => 1, pg_dumpall_globals_clean => 1, }, }, 'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => { @@ -6264,11 +6275,12 @@ qr/^GRANT SELECT ON TABLE measurement_y2006m2 TO regress_dump_test_role;/m, \Q--\E\n\n \QGRANT USAGE ON SCHEMA public TO PUBLIC;\E /xm, - like => { - clean => 1, - clean_if_exists => 1, }, + # this shouldn't ever get emitted anymore + like => {}, unlike => { binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, createdb => 1, defaults => 1, exclude_dump_test_schema => 1, @@ -6537,6 +6549,8 @@ qr/^GRANT SELECT ON TABLE measurement_y2006m2 TO regress_dump_test_role;/m, /xm, like => { binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, createdb => 1, defaults => 1, exclude_dump_test_schema => 1, @@ -6549,8 +6563,6 @@ qr/^GRANT SELECT ON TABLE measurement_y2006m2 TO regress_dump_test_role;/m, section_pre_data => 1, with_oids => 1, }, unlike => { - clean => 1, - clean_if_exists => 1, only_dump_test_schema => 1, only_dump_test_table => 1, pg_dumpall_globals_clean => 1, @@ -6576,18 +6588,18 @@ qr/^GRANT SELECT ON TABLE measurement_y2006m2 TO regress_dump_test_role;/m, exclude_test_table_data => 1, no_blobs => 1, no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, pg_dumpall_dbprivs => 1, + role => 1, schema_only => 1, section_pre_data => 1, + test_schema_plus_blobs => 1, with_oids => 1, }, unlike => { - only_dump_test_schema => 1, - only_dump_test_table => 1, pg_dumpall_globals_clean => 1, - role => 1, section_data => 1, - section_post_data => 1, - test_schema_plus_blobs => 1, }, }, + section_post_data => 1, }, }, 'REVOKE commands' => { # catch-all for REVOKE commands all_runs => 0, # catch-all |