4444#include "catalog/pg_aggregate_d.h"
4545#include "catalog/pg_am_d.h"
4646#include "catalog/pg_attribute_d.h"
47+ #include "catalog/pg_authid_d.h"
4748#include "catalog/pg_cast_d.h"
4849#include "catalog/pg_class_d.h"
4950#include "catalog/pg_default_acl_d.h"
@@ -1598,6 +1599,13 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
15981599static void
15991600selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
16001601{
1602+ /*
1603+ * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1604+ * and (for --clean) a DROP SCHEMA statement. (In the absence of
1605+ * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1606+ */
1607+ nsinfo->create = true;
1608+
16011609 /*
16021610 * If specific tables are being dumped, do not dump any complete
16031611 * namespaces. If specific namespaces are being dumped, dump just those
@@ -1633,10 +1641,15 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
16331641 * no-mans-land between being a system object and a user object. We
16341642 * don't want to dump creation or comment commands for it, because
16351643 * that complicates matters for non-superuser use of pg_dump. But we
1636- * should dump any ACL changes that have occurred for it, and of
1637- * course we should dump contained objects.
1644+ * should dump any ownership changes, security labels, and ACL
1645+ * changes, and of course we should dump contained objects. pg_dump
1646+ * ties ownership to DUMP_COMPONENT_DEFINITION. Hence, unless the
1647+ * owner is the default, dump a "definition" bearing just a comment.
16381648 */
1639- nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1649+ nsinfo->create = false;
1650+ nsinfo->dobj.dump = DUMP_COMPONENT_ALL & ~DUMP_COMPONENT_COMMENT;
1651+ if (nsinfo->nspowner == BOOTSTRAP_SUPERUSERID)
1652+ nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
16401653 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
16411654 }
16421655 else
@@ -3428,8 +3441,8 @@ getBlobs(Archive *fout)
34283441 PQExpBuffer init_racl_subquery = createPQExpBuffer();
34293442
34303443 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3431- init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3432- dopt->binary_upgrade);
3444+ init_racl_subquery, "l.lomacl", "l.lomowner",
3445+ "pip.initprivs", "'L'", dopt->binary_upgrade);
34333446
34343447 appendPQExpBuffer(blobQry,
34353448 "SELECT l.oid, (%s l.lomowner) AS rolname, "
@@ -4830,6 +4843,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
48304843 int i_tableoid;
48314844 int i_oid;
48324845 int i_nspname;
4846+ int i_nspowner;
48334847 int i_rolname;
48344848 int i_nspacl;
48354849 int i_rnspacl;
@@ -4849,11 +4863,27 @@ getNamespaces(Archive *fout, int *numNamespaces)
48494863 PQExpBuffer init_acl_subquery = createPQExpBuffer();
48504864 PQExpBuffer init_racl_subquery = createPQExpBuffer();
48514865
4866+ /*
4867+ * Bypass pg_init_privs.initprivs for the public schema. Dropping and
4868+ * recreating the schema detaches it from its pg_init_privs row, but
4869+ * an empty destination database starts with this ACL nonetheless.
4870+ * Also, we support dump/reload of public schema ownership changes.
4871+ * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
4872+ * initprivs continues to reflect the initial owner (the bootstrap
4873+ * superuser). Hence, synthesize the value that nspacl will have
4874+ * after the restore's ALTER SCHEMA OWNER.
4875+ */
48524876 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4853- init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4854- dopt->binary_upgrade);
4877+ init_racl_subquery, "n.nspacl", "n.nspowner",
4878+ "CASE WHEN n.nspname = 'public' THEN array["
4879+ " format('%s=UC/%s', "
4880+ " n.nspowner::regrole, n.nspowner::regrole),"
4881+ " format('=UC/%s', n.nspowner::regrole)]::aclitem[] "
4882+ "ELSE pip.initprivs END",
4883+ "'n'", dopt->binary_upgrade);
48554884
48564885 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4886+ "n.nspowner, "
48574887 "(%s nspowner) AS rolname, "
48584888 "%s as nspacl, "
48594889 "%s as rnspacl, "
@@ -4878,7 +4908,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
48784908 destroyPQExpBuffer(init_racl_subquery);
48794909 }
48804910 else
4881- appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4911+ appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, nspowner, "
48824912 "(%s nspowner) AS rolname, "
48834913 "nspacl, NULL as rnspacl, "
48844914 "NULL AS initnspacl, NULL as initrnspacl "
@@ -4894,6 +4924,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
48944924 i_tableoid = PQfnumber(res, "tableoid");
48954925 i_oid = PQfnumber(res, "oid");
48964926 i_nspname = PQfnumber(res, "nspname");
4927+ i_nspowner = PQfnumber(res, "nspowner");
48974928 i_rolname = PQfnumber(res, "rolname");
48984929 i_nspacl = PQfnumber(res, "nspacl");
48994930 i_rnspacl = PQfnumber(res, "rnspacl");
@@ -4907,6 +4938,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
49074938 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
49084939 AssignDumpId(&nsinfo[i].dobj);
49094940 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4941+ nsinfo[i].nspowner = atooid(PQgetvalue(res, i, i_nspowner));
49104942 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
49114943 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
49124944 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
@@ -5098,8 +5130,8 @@ getTypes(Archive *fout, int *numTypes)
50985130 PQExpBuffer initracl_subquery = createPQExpBuffer();
50995131
51005132 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5101- initracl_subquery, "t.typacl", "t.typowner", "'T'",
5102- dopt->binary_upgrade);
5133+ initracl_subquery, "t.typacl", "t.typowner",
5134+ "pip.initprivs", "'T'", dopt->binary_upgrade);
51035135
51045136 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
51055137 "t.typnamespace, "
@@ -5800,8 +5832,8 @@ getAggregates(Archive *fout, int *numAggs)
58005832 const char *agg_check;
58015833
58025834 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5803- initracl_subquery, "p.proacl", "p.proowner", "'f'",
5804- dopt->binary_upgrade);
5835+ initracl_subquery, "p.proacl", "p.proowner",
5836+ "pip.initprivs", "'f'", dopt->binary_upgrade);
58055837
58065838 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
58075839 : "p.proisagg");
@@ -6013,8 +6045,8 @@ getFuncs(Archive *fout, int *numFuncs)
60136045 const char *not_agg_check;
60146046
60156047 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
6016- initracl_subquery, "p.proacl", "p.proowner", "'f'",
6017- dopt->binary_upgrade);
6048+ initracl_subquery, "p.proacl", "p.proowner",
6049+ "pip.initprivs", "'f'", dopt->binary_upgrade);
60186050
60196051 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
60206052 : "NOT p.proisagg");
@@ -6310,13 +6342,14 @@ getTables(Archive *fout, int *numTables)
63106342
63116343 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
63126344 initracl_subquery, "c.relacl", "c.relowner",
6345+ "pip.initprivs",
63136346 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
63146347 " THEN 's' ELSE 'r' END::\"char\"",
63156348 dopt->binary_upgrade);
63166349
63176350 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
6318- attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
6319- dopt->binary_upgrade);
6351+ attinitracl_subquery, "at.attacl", "c.relowner",
6352+ "pip.initprivs", "'c'", dopt->binary_upgrade);
63206353
63216354 appendPQExpBuffer(query,
63226355 "SELECT c.tableoid, c.oid, c.relname, "
@@ -8241,8 +8274,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
82418274 PQExpBuffer initracl_subquery = createPQExpBuffer();
82428275
82438276 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8244- initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
8245- dopt->binary_upgrade);
8277+ initracl_subquery, "l.lanacl", "l.lanowner",
8278+ "pip.initprivs", "'l'", dopt->binary_upgrade);
82468279
82478280 /* pg_language has a laninline column */
82488281 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
@@ -9432,8 +9465,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
94329465 PQExpBuffer initracl_subquery = createPQExpBuffer();
94339466
94349467 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9435- initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9436- dopt->binary_upgrade);
9468+ initracl_subquery, "f.fdwacl", "f.fdwowner",
9469+ "pip.initprivs", "'F'", dopt->binary_upgrade);
94379470
94389471 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
94399472 "(%s f.fdwowner) AS rolname, "
@@ -9599,8 +9632,8 @@ getForeignServers(Archive *fout, int *numForeignServers)
95999632 PQExpBuffer initracl_subquery = createPQExpBuffer();
96009633
96019634 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9602- initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9603- dopt->binary_upgrade);
9635+ initracl_subquery, "f.srvacl", "f.srvowner",
9636+ "pip.initprivs", "'S'", dopt->binary_upgrade);
96049637
96059638 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
96069639 "(%s f.srvowner) AS rolname, "
@@ -9746,6 +9779,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
97469779
97479780 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
97489781 initracl_subquery, "defaclacl", "defaclrole",
9782+ "pip.initprivs",
97499783 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
97509784 dopt->binary_upgrade);
97519785
@@ -10363,9 +10397,19 @@ dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
1036310397
1036410398 qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
1036510399
10366- appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10367-
10368- appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10400+ if (nspinfo->create)
10401+ {
10402+ appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10403+ appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10404+ }
10405+ else
10406+ {
10407+ /* see selectDumpableNamespace() */
10408+ appendPQExpBufferStr(delq,
10409+ "-- *not* dropping schema, since initdb creates it\n");
10410+ appendPQExpBufferStr(q,
10411+ "-- *not* creating schema, since initdb creates it\n");
10412+ }
1036910413
1037010414 if (dopt->binary_upgrade)
1037110415 binary_upgrade_extension_member(q, &nspinfo->dobj,
@@ -15556,8 +15600,8 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
1555615600 PQExpBuffer initracl_subquery = createPQExpBuffer();
1555715601
1555815602 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15559- initracl_subquery, "at.attacl", "c.relowner", "'c'",
15560- dopt->binary_upgrade);
15603+ initracl_subquery, "at.attacl", "c.relowner",
15604+ "pip.initprivs", "'c'", dopt->binary_upgrade);
1556115605
1556215606 appendPQExpBuffer(query,
1556315607 "SELECT at.attname, "
0 commit comments