Skip to content

Commit 330b84d

Browse files
committed
pg_dump: Properly handle public schema ACLs with --clean
pg_dump has always handled the public schema in a special way when it comes to the "--clean" option. To wit, we do not drop or recreate the public schema in "normal" mode, but when we are run in "--clean" mode then we do drop and recreate the public schema. When running in "--clean" mode, the public schema is dropped and then recreated and it is recreated with the normal schema-default privileges of "nothing". This is unlike how the public schema starts life, which is to have CREATE and USAGE GRANT'd to the PUBLIC role, and that is what is recorded in pg_init_privs. Due to this, in "--clean" mode, pg_dump would mistakenly only dump out the set of privileges required to go from the initdb-time privileges on the public schema to whatever the current-state privileges are. If the privileges were not changed from initdb time, then no privileges would be dumped out for the public schema, but with the schema being dropped and recreated, the result was that the public schema would have no ACLs on it instead of what it should have, which is the initdb-time privileges. Practically speaking, this meant that pg_dump with --clean mode dumping a database where the ACLs on the public schema were not changed from the default would, upon restore, result in a public schema with *no* privileges GRANT'd, not matching the state of the existing database (where the initdb-time privileges would have been CREATE and USAGE to the PUBLIC role for the public schema). To fix, adjust the query in getNamespaces() to ignore the pg_init_privs entry for the public schema when running in "--clean" mode, meaning that the privileges for the public schema would be dumped, correctly, as if it was going from a newly-created schema to the current state (which is, indeed, what will happen during the restore thanks to the DROP/CREATE). Only the public schema is handled in this special way by pg_dump, no other initdb-time objects are dropped/recreated in --clean mode. Back-patch to 9.6 where the bug was introduced. Discussion: https://postgr.es/m/3534542.o3cNaKiDID%40techfox
1 parent 299990b commit 330b84d

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

src/bin/pg_dump/pg_dump.c

+21-1
Original file line numberDiff line numberDiff line change
@@ -4005,13 +4005,33 @@ getNamespaces(Archive *fout, int *numNamespaces)
40054005
"LEFT JOIN pg_init_privs pip "
40064006
"ON (n.oid = pip.objoid "
40074007
"AND pip.classoid = 'pg_namespace'::regclass "
4008-
"AND pip.objsubid = 0) ",
4008+
"AND pip.objsubid = 0",
40094009
username_subquery,
40104010
acl_subquery->data,
40114011
racl_subquery->data,
40124012
init_acl_subquery->data,
40134013
init_racl_subquery->data);
40144014

4015+
/*
4016+
* When we are doing a 'clean' run, we will be dropping and recreating
4017+
* the 'public' schema (the only object which has that kind of
4018+
* treatment in the backend and which has an entry in pg_init_privs)
4019+
* and therefore we should not consider any initial privileges in
4020+
* pg_init_privs in that case.
4021+
*
4022+
* See pg_backup_archiver.c:_printTocEntry() for the details on why
4023+
* the public schema is special in this regard.
4024+
*
4025+
* Note that if the public schema is dropped and re-created, this is
4026+
* essentially a no-op because the new public schema won't have an
4027+
* entry in pg_init_privs anyway, as the entry will be removed when
4028+
* the public schema is dropped.
4029+
*/
4030+
if (dopt->outputClean)
4031+
appendPQExpBuffer(query," AND pip.objoid <> 'public'::regnamespace");
4032+
4033+
appendPQExpBuffer(query,") ");
4034+
40154035
destroyPQExpBuffer(acl_subquery);
40164036
destroyPQExpBuffer(racl_subquery);
40174037
destroyPQExpBuffer(init_acl_subquery);

src/bin/pg_dump/t/002_pg_dump.pl

+30-2
Original file line numberDiff line numberDiff line change
@@ -3081,6 +3081,34 @@
30813081
role => 1,
30823082
test_schema_plus_blobs => 1, }, },
30833083
3084+
'GRANT USAGE ON SCHEMA public TO public' => {
3085+
regexp => qr/^
3086+
\Q--\E\n\n
3087+
\QGRANT USAGE ON SCHEMA public TO PUBLIC;\E
3088+
/xm,
3089+
like => {
3090+
clean => 1,
3091+
clean_if_exists => 1, },
3092+
unlike => {
3093+
binary_upgrade => 1,
3094+
createdb => 1,
3095+
defaults => 1,
3096+
exclude_dump_test_schema => 1,
3097+
exclude_test_table => 1,
3098+
exclude_test_table_data => 1,
3099+
no_blobs => 1,
3100+
no_owner => 1,
3101+
pg_dumpall_dbprivs => 1,
3102+
schema_only => 1,
3103+
section_pre_data => 1,
3104+
only_dump_test_schema => 1,
3105+
only_dump_test_table => 1,
3106+
pg_dumpall_globals_clean => 1,
3107+
role => 1,
3108+
section_data => 1,
3109+
section_post_data => 1,
3110+
test_schema_plus_blobs => 1, }, },
3111+
30843112
'GRANT commands' => { # catch-all for GRANT commands
30853113
all_runs => 0, # catch-all
30863114
regexp => qr/^GRANT /m,
@@ -3258,8 +3286,6 @@
32583286
/xm,
32593287
like => {
32603288
binary_upgrade => 1,
3261-
clean => 1,
3262-
clean_if_exists => 1,
32633289
createdb => 1,
32643290
defaults => 1,
32653291
exclude_dump_test_schema => 1,
@@ -3271,6 +3297,8 @@
32713297
schema_only => 1,
32723298
section_pre_data => 1, },
32733299
unlike => {
3300+
clean => 1,
3301+
clean_if_exists => 1,
32743302
only_dump_test_schema => 1,
32753303
only_dump_test_table => 1,
32763304
pg_dumpall_globals_clean => 1,

0 commit comments

Comments
 (0)