aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/aclchk.c17
-rw-r--r--src/backend/utils/adt/pg_upgrade_support.c12
-rw-r--r--src/bin/initdb/initdb.c6
-rw-r--r--src/bin/pg_dump/dumputils.c274
-rw-r--r--src/bin/pg_dump/dumputils.h9
-rw-r--r--src/bin/pg_dump/pg_dump.c1077
-rw-r--r--src/bin/pg_dump/pg_dump.h24
-rw-r--r--src/bin/pg_dump/pg_dumpall.c6
-rw-r--r--src/include/catalog/binary_upgrade.h2
-rw-r--r--src/include/catalog/pg_proc.h2
-rw-r--r--src/test/regress/expected/init_privs.out13
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/init_privs.sql11
14 files changed, 1247 insertions, 209 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index ffb6678c6a4..975fe13fcf9 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -22,6 +22,7 @@
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/xact.h"
+#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
@@ -85,6 +86,12 @@ typedef struct
DropBehavior behavior;
} InternalDefaultACL;
+/*
+ * When performing a binary-upgrade, pg_dump will call a function to set
+ * this variable to let us know that we need to populate the pg_init_privs
+ * table for the GRANT/REVOKE commands while this variable is set to true.
+ */
+bool binary_upgrade_record_init_privs = false;
static void ExecGrantStmt_oids(InternalGrant *istmt);
static void ExecGrant_Relation(InternalGrant *grantStmt);
@@ -5237,7 +5244,15 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
HeapTuple tuple;
HeapTuple oldtuple;
- if (!creating_extension)
+ /*
+ * Generally, we only record the initial privileges when an extension is
+ * being created, but because we don't actually use CREATE EXTENSION
+ * during binary upgrades with pg_upgrade, there is a variable to let us
+ * know that the GRANT and REVOKE statements being issued, while this
+ * variable is true, are for the initial privileges of the extension
+ * object and therefore we need to record them.
+ */
+ if (!creating_extension && !binary_upgrade_record_init_privs)
return;
relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index 912eadaf369..6ff035ace30 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -29,6 +29,7 @@ Datum binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS);
Datum binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS);
Datum binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS);
Datum binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS);
+Datum binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS);
#define CHECK_IS_BINARY_UPGRADE \
@@ -193,3 +194,14 @@ binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+
+Datum
+binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS)
+{
+ bool record_init_privs = PG_GETARG_BOOL(0);
+
+ CHECK_IS_BINARY_UPGRADE;
+ binary_upgrade_record_init_privs = record_init_privs;
+
+ PG_RETURN_VOID();
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 858667b3941..18a3826b003 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -2002,7 +2002,11 @@ setup_privileges(FILE *cmdfd)
char **priv_lines;
static char *privileges_setup[] = {
"UPDATE pg_class "
- " SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+ " SET relacl = (SELECT array_agg(a.acl) FROM "
+ " (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
+ " UNION SELECT unnest(pg_catalog.acldefault("
+ " CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid))"
+ " ) as a) "
" WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n",
"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 5301d3fa541..c55a2fa14ec 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -38,6 +38,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
* TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
* FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
* acls: the ACL string fetched from the database
+ * racls: the ACL string of any initial-but-now-revoked privileges
* owner: username of object owner (will be passed through fmtId); can be
* NULL or empty string to indicate "no owner known"
* prefix: string to prefix to each generated command; typically empty
@@ -54,13 +55,15 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
*/
bool
buildACLCommands(const char *name, const char *subname,
- const char *type, const char *acls, const char *owner,
- const char *prefix, int remoteVersion,
+ const char *type, const char *acls, const char *racls,
+ const char *owner, const char *prefix, int remoteVersion,
PQExpBuffer sql)
{
bool ok = true;
- char **aclitems;
- int naclitems;
+ char **aclitems = NULL;
+ char **raclitems = NULL;
+ int naclitems = 0;
+ int nraclitems = 0;
int i;
PQExpBuffer grantee,
grantor,
@@ -70,18 +73,31 @@ buildACLCommands(const char *name, const char *subname,
secondsql;
bool found_owner_privs = false;
- if (strlen(acls) == 0)
+ if (strlen(acls) == 0 && strlen(racls) == 0)
return true; /* object has default permissions */
/* treat empty-string owner same as NULL */
if (owner && *owner == '\0')
owner = NULL;
- if (!parsePGArray(acls, &aclitems, &naclitems))
+ if (strlen(acls) != 0)
{
- if (aclitems)
- free(aclitems);
- return false;
+ if (!parsePGArray(acls, &aclitems, &naclitems))
+ {
+ if (aclitems)
+ free(aclitems);
+ return false;
+ }
+ }
+
+ if (strlen(racls) != 0)
+ {
+ if (!parsePGArray(racls, &raclitems, &nraclitems))
+ {
+ if (raclitems)
+ free(raclitems);
+ return false;
+ }
}
grantee = createPQExpBuffer();
@@ -90,24 +106,101 @@ buildACLCommands(const char *name, const char *subname,
privswgo = createPQExpBuffer();
/*
- * At the end, these two will be pasted together to form the result. But
- * the owner privileges need to go before the other ones to keep the
- * dependencies valid. In recent versions this is normally the case, but
- * in old versions they come after the PUBLIC privileges and that results
- * in problems if we need to run REVOKE on the owner privileges.
+ * At the end, these two will be pasted together to form the result.
+ *
+ * For older systems we use these to ensure that the owner privileges go
+ * before the other ones, as a GRANT could create the default entry for
+ * the object, which generally includes all rights for the owner. In more
+ * recent versions we normally handle this because the owner rights come
+ * first in the ACLs, but older versions might have them after the PUBLIC
+ * privileges.
+ *
+ * For 9.6 and later systems, much of this changes. With 9.6, we check
+ * the default privileges for the objects at dump time and create two sets
+ * of ACLs- "racls" which are the ACLs to REVOKE from the object (as the
+ * object may have initial privileges on it, along with any default ACLs
+ * which are not part of the current set of privileges), and regular
+ * "acls", which are the ACLs to GRANT to the object. We handle the
+ * REVOKEs first, followed by the GRANTs.
*/
firstsql = createPQExpBuffer();
secondsql = createPQExpBuffer();
/*
- * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
- * wire-in knowledge about the default public privileges for different
- * kinds of objects.
+ * For pre-9.6 systems, we always start with REVOKE ALL FROM PUBLIC, as we
+ * don't wish to make any assumptions about what the default ACLs are, and
+ * we do not collect them during the dump phase (and racls will always be
+ * the empty set, see above).
+ *
+ * For 9.6 and later, if any revoke ACLs have been provided, then include
+ * them in 'firstsql'.
+ *
+ * Revoke ACLs happen when an object starts out life with a set of
+ * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has
+ * decided to revoke those rights. Since those objects come into being
+ * with those default privileges, we have to revoke them to match what the
+ * current state of affairs is. Note that we only started explicitly
+ * tracking such initial rights in 9.6, and prior to that all initial
+ * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'
+ * case, for initdb-created objects. Prior to 9.6, we didn't handle
+ * extensions correctly, but we do now by tracking their initial
+ * privileges, in the same way we track initdb initial privileges, see
+ * pg_init_privs.
*/
- appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
- if (subname)
- appendPQExpBuffer(firstsql, "(%s)", subname);
- appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+ if (remoteVersion < 90600)
+ {
+ Assert(nraclitems == 0);
+
+ appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
+ if (subname)
+ appendPQExpBuffer(firstsql, "(%s)", subname);
+ appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+ }
+ else
+ {
+ /* Scan individual REVOKE ACL items */
+ for (i = 0; i < nraclitems; i++)
+ {
+ if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
+ grantee, grantor, privs, privswgo))
+ {
+ ok = false;
+ break;
+ }
+
+ if (privs->len > 0 || privswgo->len > 0)
+ {
+ if (privs->len > 0)
+ {
+ appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s %s FROM ",
+ prefix, privs->data, type, name);
+ if (grantee->len == 0)
+ appendPQExpBufferStr(firstsql, "PUBLIC;\n");
+ else if (strncmp(grantee->data, "group ",
+ strlen("group ")) == 0)
+ appendPQExpBuffer(firstsql, "GROUP %s;\n",
+ fmtId(grantee->data + strlen("group ")));
+ else
+ appendPQExpBuffer(firstsql, "%s;\n",
+ fmtId(grantee->data));
+ }
+ if (privswgo->len > 0)
+ {
+ appendPQExpBuffer(firstsql,
+ "%sREVOKE GRANT OPTION FOR %s ON %s %s FROM ",
+ prefix, privswgo->data, type, name);
+ if (grantee->len == 0)
+ appendPQExpBufferStr(firstsql, "PUBLIC");
+ else if (strncmp(grantee->data, "group ",
+ strlen("group ")) == 0)
+ appendPQExpBuffer(firstsql, "GROUP %s",
+ fmtId(grantee->data + strlen("group ")));
+ else
+ appendPQExpBufferStr(firstsql, fmtId(grantee->data));
+ }
+ }
+ }
+ }
/*
* We still need some hacking though to cover the case where new default
@@ -138,7 +231,14 @@ buildACLCommands(const char *name, const char *subname,
if (privs->len > 0 || privswgo->len > 0)
{
- if (owner
+ /*
+ * Prior to 9.6, we had to handle owner privileges in a special
+ * manner by first REVOKE'ing the rights and then GRANT'ing them
+ * after. With 9.6 and above, what we need to REVOKE and what we
+ * need to GRANT is figured out when we dump and stashed into
+ * "racls" and "acls", respectivly. See above.
+ */
+ if (remoteVersion < 90600 && owner
&& strcmp(grantee->data, owner) == 0
&& strcmp(grantor->data, owner) == 0)
{
@@ -172,7 +272,14 @@ buildACLCommands(const char *name, const char *subname,
else
{
/*
- * Otherwise can assume we are starting from no privs.
+ * For systems prior to 9.6, we can assume we are starting
+ * from no privs at this point.
+ *
+ * For 9.6 and above, at this point we have issued REVOKE
+ * statements for all initial and default privileges which are
+ * no longer present on the object (as they were passed in as
+ * 'racls') and we can simply GRANT the rights which are in
+ * 'acls'.
*/
if (grantor->len > 0
&& (!owner || strcmp(owner, grantor->data) != 0))
@@ -215,9 +322,12 @@ buildACLCommands(const char *name, const char *subname,
}
/*
- * If we didn't find any owner privs, the owner must have revoked 'em all
+ * For systems prior to 9.6, if we didn't find any owner privs, the owner
+ * must have revoked 'em all.
+ *
+ * For 9.6 and above, we handle this through the 'racls'. See above.
*/
- if (!found_owner_privs && owner)
+ if (remoteVersion < 90600 && !found_owner_privs && owner)
{
appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
if (subname)
@@ -235,7 +345,11 @@ buildACLCommands(const char *name, const char *subname,
destroyPQExpBuffer(firstsql);
destroyPQExpBuffer(secondsql);
- free(aclitems);
+ if (aclitems)
+ free(aclitems);
+
+ if (raclitems)
+ free(raclitems);
return ok;
}
@@ -275,7 +389,7 @@ buildDefaultACLCommands(const char *type, const char *nspname,
appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
result = buildACLCommands("", NULL,
- type, acls, owner,
+ type, acls, "", owner,
prefix->data, remoteVersion,
sql);
@@ -555,3 +669,109 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
appendPQExpBufferStr(buffer, ";\n");
}
}
+
+/*
+ * buildACLQueries
+ *
+ * Build the subqueries to extract out the correct set of ACLs to be
+ * GRANT'd and REVOKE'd for the specific kind of object, accounting for any
+ * initial privileges (from pg_init_privs) and based on if we are in binary
+ * upgrade mode or not.
+ *
+ * Also builds subqueries to extract out the set of ACLs to go from the object
+ * default privileges to the privileges in pg_init_privs, if we are in binary
+ * upgrade mode, so that those privileges can be set up and recorded in the new
+ * cluster before the regular privileges are added on top of those.
+ */
+void
+buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
+ PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,
+ const char *acl_column, const char *acl_owner,
+ const char *obj_kind, bool binary_upgrade)
+{
+ /*
+ * To get the delta from what the permissions were at creation time
+ * (either initdb or CREATE EXTENSION) vs. what they are now, we have to
+ * look at two things:
+ *
+ * What privileges have been added, which we calculate by extracting all
+ * the current privileges (using the set of default privileges for the
+ * object type if current privileges are NULL) and then removing those
+ * which existed at creation time (again, using the set of default
+ * privileges for the object type if there were no creation time
+ * privileges).
+ *
+ * What privileges have been removed, which we calculate by extracting the
+ * privileges as they were at creation time (or the default privileges, as
+ * above), and then removing the current privileges (or the default
+ * privileges, if current privileges are NULL).
+ *
+ * As a good cross-check, both directions of these checks should result in
+ * the empty set if both the current ACL and the initial privs are NULL
+ * (meaning, in practice, that the default ACLs were there at init time
+ * and is what the current privileges are).
+ *
+ * We always perform this delta on all ACLs and expect that by the time
+ * these are run the initial privileges will be in place, even in a
+ * binary upgrade situation (see below).
+ */
+ printfPQExpBuffer(acl_subquery, "(SELECT array_agg(acl) FROM "
+ "(SELECT unnest(coalesce(%s,acldefault(%s,%s))) AS acl "
+ "EXCEPT "
+ "SELECT unnest(coalesce(pip.initprivs,acldefault(%s,%s)))) as foo)",
+ acl_column,
+ obj_kind,
+ acl_owner,
+ obj_kind,
+ acl_owner);
+
+ printfPQExpBuffer(racl_subquery, "(SELECT array_agg(acl) FROM "
+ "(SELECT unnest(coalesce(pip.initprivs,acldefault(%s,%s))) AS acl "
+ "EXCEPT "
+ "SELECT unnest(coalesce(%s,acldefault(%s,%s)))) as foo)",
+ obj_kind,
+ acl_owner,
+ acl_column,
+ obj_kind,
+ acl_owner);
+
+ /*
+ * In binary upgrade mode we don't run the extension script but instead
+ * dump out the objects independently and then recreate them. To preserve
+ * the initial privileges which were set on extension objects, we need to
+ * grab the set of GRANT and REVOKE commands necessary to get from the
+ * default privileges of an object to the initial privileges as recorded
+ * in pg_init_privs.
+ *
+ * These will then be run ahead of the regular ACL commands, which were
+ * calculated using the queries above, inside of a block which sets a flag
+ * to indicate that the backend should record the results of these GRANT
+ * and REVOKE statements into pg_init_privs. This is how we preserve the
+ * contents of that catalog across binary upgrades.
+ */
+ if (binary_upgrade)
+ {
+ printfPQExpBuffer(init_acl_subquery,
+ "CASE WHEN privtype = 'e' THEN "
+ "(SELECT array_agg(acl) FROM "
+ "(SELECT unnest(pip.initprivs) AS acl "
+ "EXCEPT "
+ "SELECT unnest(acldefault(%s,%s))) as foo) END",
+ obj_kind,
+ acl_owner);
+
+ printfPQExpBuffer(init_racl_subquery,
+ "CASE WHEN privtype = 'e' THEN "
+ "(SELECT array_agg(acl) FROM "
+ "(SELECT unnest(acldefault(%s,%s)) AS acl "
+ "EXCEPT "
+ "SELECT unnest(pip.initprivs)) as foo) END",
+ obj_kind,
+ acl_owner);
+ }
+ else
+ {
+ printfPQExpBuffer(init_acl_subquery, "NULL");
+ printfPQExpBuffer(init_racl_subquery, "NULL");
+ }
+}
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 4b404be99a9..b2fd7d37d0c 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -37,8 +37,8 @@
extern bool buildACLCommands(const char *name, const char *subname,
- const char *type, const char *acls, const char *owner,
- const char *prefix, int remoteVersion,
+ const char *type, const char *acls, const char *racls,
+ const char *owner, const char *prefix, int remoteVersion,
PQExpBuffer sql);
extern bool buildDefaultACLCommands(const char *type, const char *nspname,
const char *acls, const char *owner,
@@ -49,4 +49,9 @@ extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
extern void emitShSecLabels(PGconn *conn, PGresult *res,
PQExpBuffer buffer, const char *target, const char *objname);
+extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
+ PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,
+ const char *acl_column, const char *acl_owner,
+ const char *obj_kind, bool binary_upgrade);
+
#endif /* DUMPUTILS_H */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e3360bc4d56..33cd6651d12 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -206,7 +206,8 @@ static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name, const char *subname,
const char *tag, const char *nspname, const char *owner,
- const char *acls);
+ const char *acls, const char *racls,
+ const char *initacls, const char *initracls);
static void getDependencies(Archive *fout);
static void BuildArchiveDependencies(Archive *fout);
@@ -1268,7 +1269,7 @@ expand_table_name_patterns(Archive *fout,
* Returns true if object is an extension member, else false.
*/
static bool
-checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
+checkExtensionMembership(DumpableObject *dobj, Archive *fout)
{
ExtensionInfo *ext = findOwningExtension(dobj->catId);
@@ -1281,12 +1282,26 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
addObjectDependency(dobj, ext->dobj.dumpId);
/*
- * Normally, mark the member object as not to be dumped. But in binary
- * upgrades, we still dump the members individually, since the idea is to
- * exactly reproduce the database contents rather than replace the
- * extension contents with something different.
+ * In 9.6 and above, mark the member object to have any non-initial ACL,
+ * policies, and security lables dumped.
+ *
+ * Note that any initial ACLs (see pg_init_privs) will be removed when we
+ * extract the information about the object. We don't provide support for
+ * initial policies and security labels and it seems unlikely for those to
+ * ever exist, but we may have to revisit this later.
+ *
+ * Prior to 9.6, we do not include any extension member components.
+ *
+ * In binary upgrades, we still dump all components of the members
+ * individually, since the idea is to exactly reproduce the database
+ * contents rather than replace the extension contents with something
+ * different.
*/
- if (!dopt->binary_upgrade)
+ if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
+ dobj->dump = DUMP_COMPONENT_ACL |
+ DUMP_COMPONENT_SECLABEL |
+ DUMP_COMPONENT_POLICY;
+ else if (!fout->dopt->binary_upgrade)
dobj->dump = DUMP_COMPONENT_NONE;
else
dobj->dump = ext->dobj.dump;
@@ -1299,9 +1314,9 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
* Mark a namespace as to be dumped or not
*/
static void
-selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
+selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
{
- if (checkExtensionMembership(&nsinfo->dobj, dopt))
+ if (checkExtensionMembership(&nsinfo->dobj, fout))
return; /* extension membership overrides all else */
/*
@@ -1317,6 +1332,16 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
simple_oid_list_member(&schema_include_oids,
nsinfo->dobj.catId.oid) ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+ else if (fout->remoteVersion >= 90600 &&
+ strncmp(nsinfo->dobj.name, "pg_catalog",
+ strlen("pg_catalog")) == 0)
+
+ /*
+ * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
+ * they are interesting (and not the original ACLs which were set at
+ * initdb time, see pg_init_privs).
+ */
+ nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
strcmp(nsinfo->dobj.name, "information_schema") == 0)
nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
@@ -1337,9 +1362,9 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
* Mark a table as to be dumped or not
*/
static void
-selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
+selectDumpableTable(TableInfo *tbinfo, Archive *fout)
{
- if (checkExtensionMembership(&tbinfo->dobj, dopt))
+ if (checkExtensionMembership(&tbinfo->dobj, fout))
return; /* extension membership overrides all else */
/*
@@ -1376,7 +1401,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
* object (the table or base type).
*/
static void
-selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
+selectDumpableType(TypeInfo *tyinfo, Archive *fout)
{
/* skip complex types, except for standalone composite types */
if (OidIsValid(tyinfo->typrelid) &&
@@ -1405,7 +1430,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
*/
}
- if (checkExtensionMembership(&tyinfo->dobj, dopt))
+ if (checkExtensionMembership(&tyinfo->dobj, fout))
return; /* extension membership overrides all else */
/* Dump based on if the contents of the namespace are being dumped */
@@ -1443,15 +1468,15 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
* OID is in the range reserved for initdb.
*/
static void
-selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
+selectDumpableCast(CastInfo *cast, Archive *fout)
{
- if (checkExtensionMembership(&cast->dobj, dopt))
+ if (checkExtensionMembership(&cast->dobj, fout))
return; /* extension membership overrides all else */
if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
cast->dobj.dump = DUMP_COMPONENT_NONE;
else
- cast->dobj.dump = dopt->include_everything ?
+ cast->dobj.dump = fout->dopt->include_everything ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
}
@@ -1464,15 +1489,15 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
* language's OID is in the range reserved for initdb.
*/
static void
-selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
+selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
{
- if (checkExtensionMembership(&plang->dobj, dopt))
+ if (checkExtensionMembership(&plang->dobj, fout))
return; /* extension membership overrides all else */
if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
plang->dobj.dump = DUMP_COMPONENT_NONE;
else
- plang->dobj.dump = dopt->include_everything ?
+ plang->dobj.dump = fout->dopt->include_everything ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
}
@@ -1485,15 +1510,16 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
* method's OID is in the range reserved for initdb.
*/
static void
-selectDumpableAccessMethod(AccessMethodInfo *method, DumpOptions *dopt)
+selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
{
- if (checkExtensionMembership(&method->dobj, dopt))
+ if (checkExtensionMembership(&method->dobj, fout))
return; /* extension membership overrides all else */
if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
- method->dobj.dump = false;
+ method->dobj.dump = DUMP_COMPONENT_NONE;
else
- method->dobj.dump = dopt->include_everything;
+ method->dobj.dump = fout->dopt->include_everything ?
+ DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
}
/*
@@ -1523,9 +1549,9 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
* Use this only for object types without a special-case routine above.
*/
static void
-selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
+selectDumpableObject(DumpableObject *dobj, Archive *fout)
{
- if (checkExtensionMembership(dobj, dopt))
+ if (checkExtensionMembership(dobj, fout))
return; /* extension membership overrides all else */
/*
@@ -1535,7 +1561,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
if (dobj->namespace)
dobj->dump = dobj->namespace->dobj.dump_contains;
else
- dobj->dump = dopt->include_everything ?
+ dobj->dump = fout->dopt->include_everything ?
DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
}
@@ -2729,12 +2755,19 @@ dumpStdStrings(Archive *AH)
static void
getBlobs(Archive *fout)
{
+ DumpOptions *dopt = fout->dopt;
PQExpBuffer blobQry = createPQExpBuffer();
BlobInfo *binfo;
DumpableObject *bdata;
PGresult *res;
int ntups;
int i;
+ int i_oid;
+ int i_lomowner;
+ int i_lomacl;
+ int i_rlomacl;
+ int i_initlomacl;
+ int i_initrlomacl;
/* Verbose message */
if (g_verbose)
@@ -2744,52 +2777,102 @@ getBlobs(Archive *fout)
selectSourceSchema(fout, "pg_catalog");
/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
- if (fout->remoteVersion >= 90000)
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer init_acl_subquery = createPQExpBuffer();
+ PQExpBuffer init_racl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
+ init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
+ dopt->binary_upgrade);
+
appendPQExpBuffer(blobQry,
- "SELECT oid, (%s lomowner) AS rolname, lomacl"
+ "SELECT l.oid, (%s l.lomowner) AS rolname, "
+ "%s AS lomacl, "
+ "%s AS rlomacl, "
+ "%s AS initlomacl, "
+ "%s AS initrlomacl "
+ "FROM pg_largeobject_metadata l "
+ "LEFT JOIN pg_init_privs pip ON "
+ "(l.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')"
+ "AND pip.objsubid = 0) ",
+ username_subquery,
+ acl_subquery->data,
+ racl_subquery->data,
+ init_acl_subquery->data,
+ init_racl_subquery->data);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(init_acl_subquery);
+ destroyPQExpBuffer(init_racl_subquery);
+ }
+ else if (fout->remoteVersion >= 90000)
+ appendPQExpBuffer(blobQry,
+ "SELECT oid, (%s lomowner) AS rolname, lomacl, "
+ "NULL AS rlomacl, NULL as initlomacl, "
+ "NULL as initrlomacl "
" FROM pg_largeobject_metadata",
username_subquery);
else if (fout->remoteVersion >= 70100)
appendPQExpBufferStr(blobQry,
- "SELECT DISTINCT loid, NULL::oid, NULL::oid"
+ "SELECT DISTINCT loid, NULL::oid, NULL, "
+ "NULL AS rlomacl, NULL AS initlomacl, "
+ "NULL AS initrlomacl "
" FROM pg_largeobject");
else
appendPQExpBufferStr(blobQry,
- "SELECT oid, NULL::oid, NULL::oid"
+ "SELECT oid, NULL::oid, NULL, "
+ "NULL AS rlomacl, NULL AS initlomacl, "
+ "NULL AS initrlomacl "
" FROM pg_class WHERE relkind = 'l'");
res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
+ i_oid = PQfnumber(res, "oid");
+ i_lomowner = PQfnumber(res, "rolname");
+ i_lomacl = PQfnumber(res, "lomacl");
+ i_rlomacl = PQfnumber(res, "rlomacl");
+ i_initlomacl = PQfnumber(res, "initlomacl");
+ i_initrlomacl = PQfnumber(res, "initrlomacl");
+
ntups = PQntuples(res);
- if (ntups > 0)
+
+ /*
+ * Each large object has its own BLOB archive entry.
+ */
+ binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+
+ for (i = 0; i < ntups; i++)
{
- /*
- * Each large object has its own BLOB archive entry.
- */
- binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+ binfo[i].dobj.objType = DO_BLOB;
+ binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
+ binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&binfo[i].dobj);
- for (i = 0; i < ntups; i++)
- {
- binfo[i].dobj.objType = DO_BLOB;
- binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
- binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
- AssignDumpId(&binfo[i].dobj);
-
- binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
- if (!PQgetisnull(res, i, 1))
- binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
- else
- binfo[i].rolname = "";
- if (!PQgetisnull(res, i, 2))
- binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
- else
- binfo[i].blobacl = NULL;
- }
+ binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+ binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
+ binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
+ binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
+ binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
+ binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
- /*
- * If we have any large objects, a "BLOBS" archive entry is needed.
- * This is just a placeholder for sorting; it carries no data now.
- */
+ if (PQgetisnull(res, i, i_lomacl) && PQgetisnull(res, i, i_rlomacl) &&
+ PQgetisnull(res, i, i_initlomacl) &&
+ PQgetisnull(res, i, i_initrlomacl))
+ binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
+ }
+
+ /*
+ * If we have any large objects, a "BLOBS" archive entry is needed. This
+ * is just a placeholder for sorting; it carries no data now.
+ */
+ if (ntups > 0)
+ {
bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
bdata->objType = DO_BLOB_DATA;
bdata->catId = nilCatalogId;
@@ -2850,7 +2933,8 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
binfo->dobj.name, NULL, cquery->data,
- NULL, binfo->rolname, binfo->blobacl);
+ NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
+ binfo->initblobacl, binfo->initrblobacl);
destroyPQExpBuffer(cquery);
destroyPQExpBuffer(dquery);
@@ -3385,6 +3469,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
int i_nspname;
int i_rolname;
int i_nspacl;
+ int i_rnspacl;
+ int i_initnspacl;
+ int i_initrnspacl;
/*
* Before 7.3, there are no real namespaces; create two dummy entries, one
@@ -3401,8 +3488,11 @@ getNamespaces(Archive *fout, int *numNamespaces)
nsinfo[0].dobj.name = pg_strdup("public");
nsinfo[0].rolname = pg_strdup("");
nsinfo[0].nspacl = pg_strdup("");
+ nsinfo[0].rnspacl = pg_strdup("");
+ nsinfo[0].initnspacl = pg_strdup("");
+ nsinfo[0].initrnspacl = pg_strdup("");
- selectDumpableNamespace(&nsinfo[0], dopt);
+ selectDumpableNamespace(&nsinfo[0], fout);
nsinfo[1].dobj.objType = DO_NAMESPACE;
nsinfo[1].dobj.catId.tableoid = 0;
@@ -3411,8 +3501,11 @@ getNamespaces(Archive *fout, int *numNamespaces)
nsinfo[1].dobj.name = pg_strdup("pg_catalog");
nsinfo[1].rolname = pg_strdup("");
nsinfo[1].nspacl = pg_strdup("");
+ nsinfo[1].rnspacl = pg_strdup("");
+ nsinfo[1].initnspacl = pg_strdup("");
+ nsinfo[1].initrnspacl = pg_strdup("");
- selectDumpableNamespace(&nsinfo[1], dopt);
+ selectDumpableNamespace(&nsinfo[1], fout);
*numNamespaces = 2;
@@ -3428,10 +3521,46 @@ getNamespaces(Archive *fout, int *numNamespaces)
* we fetch all namespaces including system ones, so that every object we
* read in can be linked to a containing namespace.
*/
- appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
- "(%s nspowner) AS rolname, "
- "nspacl FROM pg_namespace",
- username_subquery);
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer init_acl_subquery = createPQExpBuffer();
+ PQExpBuffer init_racl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
+ init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
+ "(%s nspowner) AS rolname, "
+ "%s as nspacl, "
+ "%s as rnspacl, "
+ "%s as initnspacl, "
+ "%s as initrnspacl "
+ "FROM pg_namespace n "
+ "LEFT JOIN pg_init_privs pip "
+ "ON (n.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+ "AND pip.objsubid = 0) ",
+ username_subquery,
+ acl_subquery->data,
+ racl_subquery->data,
+ init_acl_subquery->data,
+ init_racl_subquery->data);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(init_acl_subquery);
+ destroyPQExpBuffer(init_racl_subquery);
+ }
+ else
+ appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+ "(%s nspowner) AS rolname, "
+ "nspacl, NULL as rnspacl, "
+ "NULL AS initnspacl, NULL as initrnspacl "
+ "FROM pg_namespace",
+ username_subquery);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -3444,6 +3573,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
i_nspname = PQfnumber(res, "nspname");
i_rolname = PQfnumber(res, "rolname");
i_nspacl = PQfnumber(res, "nspacl");
+ i_rnspacl = PQfnumber(res, "rnspacl");
+ i_initnspacl = PQfnumber(res, "initnspacl");
+ i_initrnspacl = PQfnumber(res, "initrnspacl");
for (i = 0; i < ntups; i++)
{
@@ -3454,9 +3586,25 @@ getNamespaces(Archive *fout, int *numNamespaces)
nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
+ nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
+ nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
+ nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
/* Decide whether to dump this namespace */
- selectDumpableNamespace(&nsinfo[i], dopt);
+ selectDumpableNamespace(&nsinfo[i], fout);
+
+ /*
+ * Do not try to dump ACL if the ACL is empty or the default.
+ *
+ * This is useful because, for some schemas/objects, the only
+ * component we are going to try and dump is the ACL and if we can
+ * remove that then 'dump' goes to zero/false and we don't consider
+ * this object for dumping at all later on.
+ */
+ if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
+ PQgetisnull(res, i, i_initnspacl) &&
+ PQgetisnull(res, i, i_initrnspacl))
+ nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
if (strlen(nsinfo[i].rolname) == 0)
write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
@@ -3616,6 +3764,9 @@ getTypes(Archive *fout, int *numTypes)
int i_typname;
int i_typnamespace;
int i_typacl;
+ int i_rtypacl;
+ int i_inittypacl;
+ int i_initrtypacl;
int i_rolname;
int i_typinput;
int i_typoutput;
@@ -3645,10 +3796,52 @@ getTypes(Archive *fout, int *numTypes)
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- if (fout->remoteVersion >= 90200)
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "t.typacl", "t.typowner", "'T'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
+ "t.typnamespace, "
+ "%s AS typacl, "
+ "%s AS rtypacl, "
+ "%s AS inittypacl, "
+ "%s AS initrtypacl, "
+ "(%s t.typowner) AS rolname, "
+ "t.typinput::oid AS typinput, "
+ "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
+ "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
+ "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
+ "t.typtype, t.typisdefined, "
+ "t.typname[0] = '_' AND t.typelem != 0 AND "
+ "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
+ "FROM pg_type t "
+ "LEFT JOIN pg_init_privs pip "
+ "ON (t.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+ "AND pip.objsubid = 0) ",
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data,
+ username_subquery);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 90200)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, typacl, "
+ "typnamespace, typacl, NULL as rtypacl, "
+ "NULL AS inittypacl, NULL AS initrtypacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3663,7 +3856,8 @@ getTypes(Archive *fout, int *numTypes)
else if (fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, NULL AS typacl, "
+ "typnamespace, NULL AS typacl, NULL as rtypacl, "
+ "NULL AS inittypacl, NULL AS initrtypacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3678,7 +3872,8 @@ getTypes(Archive *fout, int *numTypes)
else if (fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "typnamespace, NULL AS typacl, "
+ "typnamespace, NULL AS typacl, NULL as rtypacl, "
+ "NULL AS inittypacl, NULL AS initrtypacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3692,7 +3887,8 @@ getTypes(Archive *fout, int *numTypes)
else if (fout->remoteVersion >= 70100)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
- "0::oid AS typnamespace, NULL AS typacl, "
+ "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
+ "NULL AS inittypacl, NULL AS initrtypacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3708,7 +3904,8 @@ getTypes(Archive *fout, int *numTypes)
appendPQExpBuffer(query, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
"oid, typname, "
- "0::oid AS typnamespace, NULL AS typacl, "
+ "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
+ "NULL AS inittypacl, NULL AS initrtypacl, "
"(%s typowner) AS rolname, "
"typinput::oid AS typinput, "
"typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3731,6 +3928,9 @@ getTypes(Archive *fout, int *numTypes)
i_typname = PQfnumber(res, "typname");
i_typnamespace = PQfnumber(res, "typnamespace");
i_typacl = PQfnumber(res, "typacl");
+ i_rtypacl = PQfnumber(res, "rtypacl");
+ i_inittypacl = PQfnumber(res, "inittypacl");
+ i_initrtypacl = PQfnumber(res, "initrtypacl");
i_rolname = PQfnumber(res, "rolname");
i_typinput = PQfnumber(res, "typinput");
i_typoutput = PQfnumber(res, "typoutput");
@@ -3754,6 +3954,9 @@ getTypes(Archive *fout, int *numTypes)
tyinfo[i].dobj.catId.oid);
tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
+ tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
+ tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
+ tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
@@ -3771,7 +3974,13 @@ getTypes(Archive *fout, int *numTypes)
tyinfo[i].isArray = false;
/* Decide whether we want to dump it */
- selectDumpableType(&tyinfo[i], dopt);
+ selectDumpableType(&tyinfo[i], fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
+ PQgetisnull(res, i, i_inittypacl) &&
+ PQgetisnull(res, i, i_initrtypacl))
+ tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
/*
* If it's a domain, fetch info about its constraints, if any
@@ -3879,7 +4088,6 @@ getTypes(Archive *fout, int *numTypes)
OprInfo *
getOperators(Archive *fout, int *numOprs)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -3965,7 +4173,7 @@ getOperators(Archive *fout, int *numOprs)
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
/* Decide whether we want to dump it */
- selectDumpableObject(&(oprinfo[i].dobj), dopt);
+ selectDumpableObject(&(oprinfo[i].dobj), fout);
if (strlen(oprinfo[i].rolname) == 0)
write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
@@ -3989,7 +4197,6 @@ getOperators(Archive *fout, int *numOprs)
CollInfo *
getCollations(Archive *fout, int *numCollations)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4051,7 +4258,7 @@ getCollations(Archive *fout, int *numCollations)
collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
- selectDumpableObject(&(collinfo[i].dobj), dopt);
+ selectDumpableObject(&(collinfo[i].dobj), fout);
}
PQclear(res);
@@ -4071,7 +4278,6 @@ getCollations(Archive *fout, int *numCollations)
ConvInfo *
getConversions(Archive *fout, int *numConversions)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4133,7 +4339,7 @@ getConversions(Archive *fout, int *numConversions)
convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
- selectDumpableObject(&(convinfo[i].dobj), dopt);
+ selectDumpableObject(&(convinfo[i].dobj), fout);
}
PQclear(res);
@@ -4153,7 +4359,6 @@ getConversions(Archive *fout, int *numConversions)
AccessMethodInfo *
getAccessMethods(Archive *fout, int *numAccessMethods)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4207,7 +4412,7 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
/* Decide whether we want to dump it */
- selectDumpableAccessMethod(&(aminfo[i]), dopt);
+ selectDumpableAccessMethod(&(aminfo[i]), fout);
}
PQclear(res);
@@ -4228,7 +4433,6 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
OpclassInfo *
getOpclasses(Archive *fout, int *numOpclasses)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4300,7 +4504,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
- selectDumpableObject(&(opcinfo[i].dobj), dopt);
+ selectDumpableObject(&(opcinfo[i].dobj), fout);
if (fout->remoteVersion >= 70300)
{
@@ -4327,7 +4531,6 @@ getOpclasses(Archive *fout, int *numOpclasses)
OpfamilyInfo *
getOpfamilies(Archive *fout, int *numOpfamilies)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -4389,7 +4592,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
- selectDumpableObject(&(opfinfo[i].dobj), dopt);
+ selectDumpableObject(&(opfinfo[i].dobj), fout);
if (fout->remoteVersion >= 70300)
{
@@ -4430,22 +4633,79 @@ getAggregates(Archive *fout, int *numAggs)
int i_proargtypes;
int i_rolname;
int i_aggacl;
+ int i_raggacl;
+ int i_initaggacl;
+ int i_initraggacl;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
/*
- * Find all user-defined aggregates. See comment in getFuncs() for the
+ * Find all interesting aggregates. See comment in getFuncs() for the
* rationale behind the filtering logic.
*/
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "p.proacl", "p.proowner", "'f'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
+ "p.proname AS aggname, "
+ "p.pronamespace AS aggnamespace, "
+ "p.pronargs, p.proargtypes, "
+ "(%s p.proowner) AS rolname, "
+ "%s AS aggacl, "
+ "%s AS raggacl, "
+ "%s AS initaggacl, "
+ "%s AS initraggacl "
+ "FROM pg_proc p "
+ "LEFT JOIN pg_init_privs pip ON "
+ "(p.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+ "AND pip.objsubid = 0) "
+ "WHERE p.proisagg AND ("
+ "p.pronamespace != "
+ "(SELECT oid FROM pg_namespace "
+ "WHERE nspname = 'pg_catalog') OR "
+ "EXISTS (SELECT * FROM pg_init_privs pip "
+ "WHERE p.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class "
+ "WHERE relname = 'pg_proc') "
+ "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+ username_subquery,
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data);
+ if (dopt->binary_upgrade)
+ appendPQExpBufferStr(query,
+ " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+ "classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND "
+ "refclassid = 'pg_extension'::regclass AND "
+ "deptype = 'e')");
+ appendPQExpBufferChar(query, ')');
- if (fout->remoteVersion >= 80200)
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 80200)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
"pronamespace AS aggnamespace, "
"pronargs, proargtypes, "
"(%s proowner) AS rolname, "
- "proacl AS aggacl "
+ "proacl AS aggacl, "
+ "NULL AS raggacl, "
+ "NULL AS initaggacl, NULL AS initraggacl "
"FROM pg_proc p "
"WHERE proisagg AND ("
"pronamespace != "
@@ -4468,7 +4728,9 @@ getAggregates(Archive *fout, int *numAggs)
"CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
"proargtypes, "
"(%s proowner) AS rolname, "
- "proacl AS aggacl "
+ "proacl AS aggacl, "
+ "NULL AS raggacl, "
+ "NULL AS initaggacl, NULL AS initraggacl "
"FROM pg_proc "
"WHERE proisagg "
"AND pronamespace != "
@@ -4482,7 +4744,9 @@ getAggregates(Archive *fout, int *numAggs)
"CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
"aggbasetype AS proargtypes, "
"(%s aggowner) AS rolname, "
- "NULL AS aggacl "
+ "NULL AS aggacl, "
+ "NULL AS raggacl, "
+ "NULL AS initaggacl, NULL AS initraggacl "
"FROM pg_aggregate "
"where oid > '%u'::oid",
username_subquery,
@@ -4497,7 +4761,9 @@ getAggregates(Archive *fout, int *numAggs)
"CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
"aggbasetype AS proargtypes, "
"(%s aggowner) AS rolname, "
- "NULL AS aggacl "
+ "NULL AS aggacl, "
+ "NULL AS raggacl, "
+ "NULL AS initaggacl, NULL AS initraggacl "
"FROM pg_aggregate "
"where oid > '%u'::oid",
username_subquery,
@@ -4519,6 +4785,9 @@ getAggregates(Archive *fout, int *numAggs)
i_proargtypes = PQfnumber(res, "proargtypes");
i_rolname = PQfnumber(res, "rolname");
i_aggacl = PQfnumber(res, "aggacl");
+ i_raggacl = PQfnumber(res, "raggacl");
+ i_initaggacl = PQfnumber(res, "initaggacl");
+ i_initraggacl = PQfnumber(res, "initraggacl");
for (i = 0; i < ntups; i++)
{
@@ -4538,6 +4807,9 @@ getAggregates(Archive *fout, int *numAggs)
agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+ agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
+ agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
+ agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (agginfo[i].aggfn.nargs == 0)
agginfo[i].aggfn.argtypes = NULL;
@@ -4554,7 +4826,13 @@ getAggregates(Archive *fout, int *numAggs)
}
/* Decide whether we want to dump it */
- selectDumpableObject(&(agginfo[i].aggfn.dobj), dopt);
+ selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
+ PQgetisnull(res, i, i_initaggacl) &&
+ PQgetisnull(res, i, i_initraggacl))
+ agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -4590,17 +4868,21 @@ getFuncs(Archive *fout, int *numFuncs)
int i_proargtypes;
int i_prorettype;
int i_proacl;
+ int i_rproacl;
+ int i_initproacl;
+ int i_initrproacl;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
/*
- * Find all user-defined functions. Normally we can exclude functions in
- * pg_catalog, which is worth doing since there are several thousand of
- * 'em. However, there are some extensions that create functions in
- * pg_catalog. In normal dumps we can still ignore those --- but in
- * binary-upgrade mode, we must dump the member objects of the extension,
- * so be sure to fetch any such functions.
+ * Find all interesting functions. We include functions in pg_catalog, if
+ * they have an ACL different from what we set at initdb time (which is
+ * saved in pg_init_privs for us to perform this check). There may also
+ * be functions which are members of extensions which we must dump if we
+ * are in binary upgrade mode (we'll mark those functions as to-be-dumped
+ * when we check if the extension is to-be-dumped and we're in binary
+ * upgrade mode).
*
* Also, in 9.2 and up, exclude functions that are internally dependent on
* something else, since presumably those will be created as a result of
@@ -4609,12 +4891,69 @@ getFuncs(Archive *fout, int *numFuncs)
* because the constructors don't have any dependencies the range type
* doesn't have; otherwise we might not get creation ordering correct.
*/
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
- if (fout->remoteVersion >= 70300)
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "p.proacl", "p.proowner", "'f'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query,
+ "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
+ "p.pronargs, p.proargtypes, p.prorettype, "
+ "%s AS proacl, "
+ "%s AS rproacl, "
+ "%s AS initproacl, "
+ "%s AS initrproacl, "
+ "p.pronamespace, "
+ "(%s p.proowner) AS rolname "
+ "FROM pg_proc p "
+ "LEFT JOIN pg_init_privs pip ON "
+ "(p.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+ "AND pip.objsubid = 0) "
+ "WHERE NOT proisagg "
+ "AND NOT EXISTS (SELECT 1 FROM pg_depend "
+ "WHERE classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND deptype = 'i') AND ("
+ "pronamespace != "
+ "(SELECT oid FROM pg_namespace "
+ "WHERE nspname = 'pg_catalog') OR "
+ "EXISTS (SELECT * FROM pg_init_privs pip "
+ "WHERE p.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class "
+ "WHERE relname = 'pg_proc') "
+ "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data,
+ username_subquery);
+ if (dopt->binary_upgrade)
+ appendPQExpBufferStr(query,
+ "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+ "classid = 'pg_proc'::regclass AND "
+ "objid = p.oid AND "
+ "refclassid = 'pg_extension'::regclass AND "
+ "deptype = 'e')");
+ appendPQExpBufferChar(query, ')');
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query,
"SELECT tableoid, oid, proname, prolang, "
"pronargs, proargtypes, prorettype, proacl, "
+ "NULL as rproacl, "
+ "NULL as initproacl, NULL AS initrproacl, "
"pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc p "
@@ -4643,6 +4982,8 @@ getFuncs(Archive *fout, int *numFuncs)
"SELECT tableoid, oid, proname, prolang, "
"pronargs, proargtypes, prorettype, "
"NULL AS proacl, "
+ "NULL AS rproacl, "
+ "NULL as initproacl, NULL AS initrproacl, "
"0::oid AS pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc "
@@ -4659,6 +5000,8 @@ getFuncs(Archive *fout, int *numFuncs)
"oid, proname, prolang, "
"pronargs, proargtypes, prorettype, "
"NULL AS proacl, "
+ "NULL AS rproacl, "
+ "NULL as initproacl, NULL AS initrproacl, "
"0::oid AS pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc "
@@ -4685,6 +5028,9 @@ getFuncs(Archive *fout, int *numFuncs)
i_proargtypes = PQfnumber(res, "proargtypes");
i_prorettype = PQfnumber(res, "prorettype");
i_proacl = PQfnumber(res, "proacl");
+ i_rproacl = PQfnumber(res, "rproacl");
+ i_initproacl = PQfnumber(res, "initproacl");
+ i_initrproacl = PQfnumber(res, "initrproacl");
for (i = 0; i < ntups; i++)
{
@@ -4701,6 +5047,9 @@ getFuncs(Archive *fout, int *numFuncs)
finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
+ finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
+ finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
+ finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
if (finfo[i].nargs == 0)
finfo[i].argtypes = NULL;
@@ -4712,7 +5061,13 @@ getFuncs(Archive *fout, int *numFuncs)
}
/* Decide whether we want to dump it */
- selectDumpableObject(&(finfo[i].dobj), dopt);
+ selectDumpableObject(&(finfo[i].dobj), fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
+ PQgetisnull(res, i, i_initproacl) &&
+ PQgetisnull(res, i, i_initrproacl))
+ finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
if (strlen(finfo[i].rolname) == 0)
write_msg(NULL,
@@ -4729,7 +5084,7 @@ getFuncs(Archive *fout, int *numFuncs)
/*
* getTables
- * read all the user-defined tables (no indexes, no catalogs)
+ * read all the tables (no indexes)
* in the system catalogs return them in the TableInfo* structure
*
* numTables is set to the number of tables read in
@@ -4749,6 +5104,9 @@ getTables(Archive *fout, int *numTables)
int i_relnamespace;
int i_relkind;
int i_relacl;
+ int i_rrelacl;
+ int i_initrelacl;
+ int i_initrrelacl;
int i_rolname;
int i_relchecks;
int i_relhastriggers;
@@ -4797,7 +5155,77 @@ getTables(Archive *fout, int *numTables)
* we cannot correctly identify inherited columns, owned sequences, etc.
*/
- if (fout->remoteVersion >= 90500)
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ /*
+ * Left join to pick up dependency info linking sequences to their
+ * owning column, if any (note this dependency is AUTO as of 8.2)
+ *
+ * Left join to detect if any privileges are still as-set-at-init, in
+ * which case we won't dump out ACL commands for those.
+ */
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "c.relacl", "c.relowner",
+ "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query,
+ "SELECT c.tableoid, c.oid, c.relname, "
+ "%s AS relacl, %s as rrelacl, "
+ "%s AS initrelacl, %s as initrrelacl, "
+ "c.relkind, c.relnamespace, "
+ "(%s c.relowner) AS rolname, "
+ "c.relchecks, c.relhastriggers, "
+ "c.relhasindex, c.relhasrules, c.relhasoids, "
+ "c.relrowsecurity, c.relforcerowsecurity, "
+ "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
+ "tc.relfrozenxid AS tfrozenxid, "
+ "tc.relminmxid AS tminmxid, "
+ "c.relpersistence, c.relispopulated, "
+ "c.relreplident, c.relpages, "
+ "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "d.refobjid AS owning_tab, "
+ "d.refobjsubid AS owning_col, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+ "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+ "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
+ "tc.reloptions AS toast_reloptions "
+ "FROM pg_class c "
+ "LEFT JOIN pg_depend d ON "
+ "(c.relkind = '%c' AND "
+ "d.classid = c.tableoid AND d.objid = c.oid AND "
+ "d.objsubid = 0 AND "
+ "d.refclassid = c.tableoid AND d.deptype = 'a') "
+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+ "LEFT JOIN pg_init_privs pip ON "
+ "(c.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class "
+ "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
+ "ORDER BY c.oid",
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data,
+ username_subquery,
+ RELKIND_SEQUENCE,
+ RELKIND_RELATION, RELKIND_SEQUENCE,
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+ RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 90500)
{
/*
* Left join to pick up dependency info linking sequences to their
@@ -4805,7 +5233,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4846,7 +5277,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4888,7 +5322,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4930,7 +5367,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4970,7 +5410,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5009,7 +5452,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5048,7 +5494,10 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
- "c.relacl, c.relkind, c.relnamespace, "
+ "c.relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "c.relkind, "
+ "c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5087,7 +5536,9 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
- "relacl, relkind, relnamespace, "
+ "relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "relkind, relnamespace, "
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
@@ -5125,7 +5576,9 @@ getTables(Archive *fout, int *numTables)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
- "relacl, relkind, relnamespace, "
+ "relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "relkind, relnamespace, "
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, "
@@ -5158,7 +5611,10 @@ getTables(Archive *fout, int *numTables)
else if (fout->remoteVersion >= 70200)
{
appendPQExpBuffer(query,
- "SELECT tableoid, oid, relname, relacl, relkind, "
+ "SELECT tableoid, oid, relname, relacl, "
+ "NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "relkind, "
"0::oid AS relnamespace, "
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5186,7 +5642,10 @@ getTables(Archive *fout, int *numTables)
{
/* all tables have oids in 7.1 */
appendPQExpBuffer(query,
- "SELECT tableoid, oid, relname, relacl, relkind, "
+ "SELECT tableoid, oid, relname, relacl, "
+ "NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
+ "relkind, "
"0::oid AS relnamespace, "
"(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5220,7 +5679,8 @@ getTables(Archive *fout, int *numTables)
appendPQExpBuffer(query,
"SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
- "oid, relname, relacl, "
+ "oid, relname, relacl, NULL as rrelacl, "
+ "NULL AS initrelacl, NULL AS initrrelacl, "
"CASE WHEN relhasrules and relkind = 'r' "
" and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
" r.ev_class = c.oid AND r.ev_type = '1') "
@@ -5274,6 +5734,9 @@ getTables(Archive *fout, int *numTables)
i_relname = PQfnumber(res, "relname");
i_relnamespace = PQfnumber(res, "relnamespace");
i_relacl = PQfnumber(res, "relacl");
+ i_rrelacl = PQfnumber(res, "rrelacl");
+ i_initrelacl = PQfnumber(res, "initrelacl");
+ i_initrrelacl = PQfnumber(res, "initrrelacl");
i_relkind = PQfnumber(res, "relkind");
i_rolname = PQfnumber(res, "rolname");
i_relchecks = PQfnumber(res, "relchecks");
@@ -5328,6 +5791,9 @@ getTables(Archive *fout, int *numTables)
tblinfo[i].dobj.catId.oid);
tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
+ tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
+ tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
+ tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -5375,7 +5841,7 @@ getTables(Archive *fout, int *numTables)
if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
else
- selectDumpableTable(&tblinfo[i], dopt);
+ selectDumpableTable(&tblinfo[i], fout);
tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
@@ -6461,7 +6927,6 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
EventTriggerInfo *
getEventTriggers(Archive *fout, int *numEventTriggers)
{
- DumpOptions *dopt = fout->dopt;
int i;
PQExpBuffer query;
PGresult *res;
@@ -6531,7 +6996,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
/* Decide whether we want to dump it */
- selectDumpableObject(&(evtinfo[i].dobj), dopt);
+ selectDumpableObject(&(evtinfo[i].dobj), fout);
}
PQclear(res);
@@ -6567,17 +7032,59 @@ getProcLangs(Archive *fout, int *numProcLangs)
int i_laninline;
int i_lanvalidator;
int i_lanacl;
+ int i_rlanacl;
+ int i_initlanacl;
+ int i_initrlanacl;
int i_lanowner;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- if (fout->remoteVersion >= 90000)
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
+ dopt->binary_upgrade);
+
+ /* pg_language has a laninline column */
+ appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
+ "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
+ "l.laninline, l.lanvalidator, "
+ "%s AS lanacl, "
+ "%s AS rlanacl, "
+ "%s AS initlanacl, "
+ "%s AS initrlanacl, "
+ "(%s l.lanowner) AS lanowner "
+ "FROM pg_language l "
+ "LEFT JOIN pg_init_privs pip "
+ "ON (l.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+ "AND pip.objsubid = 0) "
+ "WHERE l.lanispl "
+ "ORDER BY l.oid",
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data,
+ username_subquery);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 90000)
{
/* pg_language has a laninline column */
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
- "laninline, lanvalidator, lanacl, "
+ "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"(%s lanowner) AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6590,6 +7097,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"(%s lanowner) AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6602,6 +7111,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"(%s '10') AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6614,6 +7125,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"(%s '1') AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6626,6 +7139,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, lanvalidator, lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"NULL AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6636,6 +7151,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"NULL AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6648,6 +7165,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
"oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+ "NULL AS rlanacl, "
+ "NULL AS initlanacl, NULL AS initrlanacl, "
"NULL AS lanowner "
"FROM pg_language "
"WHERE lanispl "
@@ -6670,6 +7189,9 @@ getProcLangs(Archive *fout, int *numProcLangs)
i_laninline = PQfnumber(res, "laninline");
i_lanvalidator = PQfnumber(res, "lanvalidator");
i_lanacl = PQfnumber(res, "lanacl");
+ i_rlanacl = PQfnumber(res, "rlanacl");
+ i_initlanacl = PQfnumber(res, "initlanacl");
+ i_initrlanacl = PQfnumber(res, "initrlanacl");
i_lanowner = PQfnumber(res, "lanowner");
for (i = 0; i < ntups; i++)
@@ -6685,10 +7207,19 @@ getProcLangs(Archive *fout, int *numProcLangs)
planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
+ planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
+ planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
+ planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
/* Decide whether we want to dump it */
- selectDumpableProcLang(&(planginfo[i]), dopt);
+ selectDumpableProcLang(&(planginfo[i]), fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
+ PQgetisnull(res, i, i_initlanacl) &&
+ PQgetisnull(res, i, i_initrlanacl))
+ planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
if (fout->remoteVersion < 70300)
{
@@ -6721,7 +7252,6 @@ getProcLangs(Archive *fout, int *numProcLangs)
CastInfo *
getCasts(Archive *fout, int *numCasts)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -6827,7 +7357,7 @@ getCasts(Archive *fout, int *numCasts)
}
/* Decide whether we want to dump it */
- selectDumpableCast(&(castinfo[i]), dopt);
+ selectDumpableCast(&(castinfo[i]), fout);
}
PQclear(res);
@@ -6863,7 +7393,6 @@ get_language_name(Archive *fout, Oid langid)
TransformInfo *
getTransforms(Archive *fout, int *numTransforms)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -6938,7 +7467,7 @@ getTransforms(Archive *fout, int *numTransforms)
free(lanname);
/* Decide whether we want to dump it */
- selectDumpableObject(&(transforminfo[i].dobj), dopt);
+ selectDumpableObject(&(transforminfo[i].dobj), fout);
}
PQclear(res);
@@ -7549,7 +8078,6 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
TSParserInfo *
getTSParsers(Archive *fout, int *numTSParsers)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -7622,7 +8150,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
/* Decide whether we want to dump it */
- selectDumpableObject(&(prsinfo[i].dobj), dopt);
+ selectDumpableObject(&(prsinfo[i].dobj), fout);
}
PQclear(res);
@@ -7642,7 +8170,6 @@ getTSParsers(Archive *fout, int *numTSParsers)
TSDictInfo *
getTSDictionaries(Archive *fout, int *numTSDicts)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -7708,7 +8235,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
/* Decide whether we want to dump it */
- selectDumpableObject(&(dictinfo[i].dobj), dopt);
+ selectDumpableObject(&(dictinfo[i].dobj), fout);
}
PQclear(res);
@@ -7728,7 +8255,6 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
TSTemplateInfo *
getTSTemplates(Archive *fout, int *numTSTemplates)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -7786,7 +8312,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
/* Decide whether we want to dump it */
- selectDumpableObject(&(tmplinfo[i].dobj), dopt);
+ selectDumpableObject(&(tmplinfo[i].dobj), fout);
}
PQclear(res);
@@ -7806,7 +8332,6 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
TSConfigInfo *
getTSConfigurations(Archive *fout, int *numTSConfigs)
{
- DumpOptions *dopt = fout->dopt;
PGresult *res;
int ntups;
int i;
@@ -7865,7 +8390,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
/* Decide whether we want to dump it */
- selectDumpableObject(&(cfginfo[i].dobj), dopt);
+ selectDumpableObject(&(cfginfo[i].dobj), fout);
}
PQclear(res);
@@ -7898,6 +8423,9 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
int i_fdwhandler;
int i_fdwvalidator;
int i_fdwacl;
+ int i_rfdwacl;
+ int i_initfdwacl;
+ int i_initrfdwacl;
int i_fdwoptions;
/* Before 8.4, there are no foreign-data wrappers */
@@ -7912,12 +8440,55 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- if (fout->remoteVersion >= 90100)
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
+ "(%s f.fdwowner) AS rolname, "
+ "f.fdwhandler::pg_catalog.regproc, "
+ "f.fdwvalidator::pg_catalog.regproc, "
+ "%s AS fdwacl, "
+ "%s AS rfdwacl, "
+ "%s AS initfdwacl, "
+ "%s AS initrfdwacl, "
+ "array_to_string(ARRAY("
+ "SELECT quote_ident(option_name) || ' ' || "
+ "quote_literal(option_value) "
+ "FROM pg_options_to_table(f.fdwoptions) "
+ "ORDER BY option_name"
+ "), E',\n ') AS fdwoptions "
+ "FROM pg_foreign_data_wrapper f "
+ "LEFT JOIN pg_init_privs pip "
+ "ON (f.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+ "AND pip.objsubid = 0) ",
+ username_subquery,
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else if (fout->remoteVersion >= 90100)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
"(%s fdwowner) AS rolname, "
"fdwhandler::pg_catalog.regproc, "
"fdwvalidator::pg_catalog.regproc, fdwacl, "
+ "NULL as rfdwacl, "
+ "NULL as initfdwacl, NULL AS initrfdwacl, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
@@ -7933,6 +8504,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
"(%s fdwowner) AS rolname, "
"'-' AS fdwhandler, "
"fdwvalidator::pg_catalog.regproc, fdwacl, "
+ "NULL as rfdwacl, "
+ "NULL as initfdwacl, NULL AS initrfdwacl, "
"array_to_string(ARRAY("
"SELECT quote_ident(option_name) || ' ' || "
"quote_literal(option_value) "
@@ -7957,6 +8530,9 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
i_fdwhandler = PQfnumber(res, "fdwhandler");
i_fdwvalidator = PQfnumber(res, "fdwvalidator");
i_fdwacl = PQfnumber(res, "fdwacl");
+ i_rfdwacl = PQfnumber(res, "rfdwacl");
+ i_initfdwacl = PQfnumber(res, "initfdwacl");
+ i_initrfdwacl = PQfnumber(res, "initrfdwacl");
i_fdwoptions = PQfnumber(res, "fdwoptions");
for (i = 0; i < ntups; i++)
@@ -7972,9 +8548,18 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
+ fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
+ fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
+ fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
/* Decide whether we want to dump it */
- selectDumpableObject(&(fdwinfo[i].dobj), dopt);
+ selectDumpableObject(&(fdwinfo[i].dobj), fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
+ PQgetisnull(res, i, i_initfdwacl) &&
+ PQgetisnull(res, i, i_initrfdwacl))
+ fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -8008,6 +8593,9 @@ getForeignServers(Archive *fout, int *numForeignServers)
int i_srvtype;
int i_srvversion;
int i_srvacl;
+ int i_rsrvacl;
+ int i_initsrvacl;
+ int i_initrsrvacl;
int i_srvoptions;
/* Before 8.4, there are no foreign servers */
@@ -8022,17 +8610,62 @@ getForeignServers(Archive *fout, int *numForeignServers)
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
- appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
- "(%s srvowner) AS rolname, "
- "srvfdw, srvtype, srvversion, srvacl,"
- "array_to_string(ARRAY("
- "SELECT quote_ident(option_name) || ' ' || "
- "quote_literal(option_value) "
- "FROM pg_options_to_table(srvoptions) "
- "ORDER BY option_name"
- "), E',\n ') AS srvoptions "
- "FROM pg_foreign_server",
- username_subquery);
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
+ "(%s f.srvowner) AS rolname, "
+ "f.srvfdw, f.srvtype, f.srvversion, "
+ "%s AS srvacl, "
+ "%s AS rsrvacl, "
+ "%s AS initsrvacl, "
+ "%s AS initrsrvacl, "
+ "array_to_string(ARRAY("
+ "SELECT quote_ident(option_name) || ' ' || "
+ "quote_literal(option_value) "
+ "FROM pg_options_to_table(f.srvoptions) "
+ "ORDER BY option_name"
+ "), E',\n ') AS srvoptions "
+ "FROM pg_foreign_server f "
+ "LEFT JOIN pg_init_privs pip "
+ "ON (f.oid = pip.objoid AND pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+ "AND pip.objsubid = 0) ",
+ username_subquery,
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+ "(%s srvowner) AS rolname, "
+ "srvfdw, srvtype, srvversion, srvacl, "
+ "NULL AS rsrvacl, "
+ "NULL AS initsrvacl, NULL AS initrsrvacl, "
+ "array_to_string(ARRAY("
+ "SELECT quote_ident(option_name) || ' ' || "
+ "quote_literal(option_value) "
+ "FROM pg_options_to_table(srvoptions) "
+ "ORDER BY option_name"
+ "), E',\n ') AS srvoptions "
+ "FROM pg_foreign_server",
+ username_subquery);
+ }
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -8049,6 +8682,9 @@ getForeignServers(Archive *fout, int *numForeignServers)
i_srvtype = PQfnumber(res, "srvtype");
i_srvversion = PQfnumber(res, "srvversion");
i_srvacl = PQfnumber(res, "srvacl");
+ i_rsrvacl = PQfnumber(res, "rsrvacl");
+ i_initsrvacl = PQfnumber(res, "initsrvacl");
+ i_initrsrvacl = PQfnumber(res, "initrsrvacl");
i_srvoptions = PQfnumber(res, "srvoptions");
for (i = 0; i < ntups; i++)
@@ -8065,9 +8701,18 @@ getForeignServers(Archive *fout, int *numForeignServers)
srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
+ srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
+ srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
+ srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
/* Decide whether we want to dump it */
- selectDumpableObject(&(srvinfo[i].dobj), dopt);
+ selectDumpableObject(&(srvinfo[i].dobj), fout);
+
+ /* Do not try to dump ACL if no ACL exists. */
+ if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
+ PQgetisnull(res, i, i_initsrvacl) &&
+ PQgetisnull(res, i, i_initrsrvacl))
+ srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
}
PQclear(res);
@@ -8692,7 +9337,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
qnspname, NULL, nspinfo->dobj.name, NULL,
- nspinfo->rolname, nspinfo->nspacl);
+ nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
+ nspinfo->initnspacl, nspinfo->initrnspacl);
free(qnspname);
@@ -8987,7 +9633,8 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -9125,7 +9772,8 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -9200,7 +9848,8 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
destroyPQExpBuffer(q);
destroyPQExpBuffer(delq);
@@ -9594,7 +10243,8 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -9762,7 +10412,8 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
/* Dump any per-constraint comments */
for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9997,7 +10648,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
qtypname, NULL, tyinfo->dobj.name,
tyinfo->dobj.namespace->dobj.name,
- tyinfo->rolname, tyinfo->typacl);
+ tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+ tyinfo->inittypacl, tyinfo->initrtypacl);
PQclear(res);
destroyPQExpBuffer(q);
@@ -10315,7 +10967,8 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
qlanname, NULL, plang->dobj.name,
lanschema,
- plang->lanowner, plang->lanacl);
+ plang->lanowner, plang->lanacl, plang->rlanacl,
+ plang->initlanacl, plang->initrlanacl);
free(qlanname);
@@ -10986,7 +11639,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
funcsig, NULL, funcsig_tag,
finfo->dobj.namespace->dobj.name,
- finfo->rolname, finfo->proacl);
+ finfo->rolname, finfo->proacl, finfo->rproacl,
+ finfo->initproacl, finfo->initrproacl);
PQclear(res);
@@ -13069,7 +13723,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"FUNCTION",
aggsig, NULL, aggsig_tag,
agginfo->aggfn.dobj.namespace->dobj.name,
- agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+ agginfo->aggfn.rolname, agginfo->aggfn.proacl,
+ agginfo->aggfn.rproacl,
+ agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
free(aggsig);
if (aggfullsig)
@@ -13513,7 +14169,8 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
"FOREIGN DATA WRAPPER",
qfdwname, NULL, fdwinfo->dobj.name,
NULL, fdwinfo->rolname,
- fdwinfo->fdwacl);
+ fdwinfo->fdwacl, fdwinfo->rfdwacl,
+ fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
/* Dump Foreign Data Wrapper Comments */
if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13609,7 +14266,8 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
"FOREIGN SERVER",
qsrvname, NULL, srvinfo->dobj.name,
NULL, srvinfo->rolname,
- srvinfo->srvacl);
+ srvinfo->srvacl, srvinfo->rsrvacl,
+ srvinfo->initsrvacl, srvinfo->initrsrvacl);
/* Dump user mappings */
if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -13788,7 +14446,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
tag->data,
- daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
+ daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
NULL,
daclinfo->defaclrole,
false, "DEFAULT ACL", SECTION_POST_DATA,
@@ -13815,13 +14473,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
* 'owner' is the owner, NULL if there is no owner (for languages).
* 'acls' is the string read out of the fooacl system catalog field;
* it will be parsed here.
+ * 'racls' contains any initial ACLs that the object had which have now been
+ * revoked by the user, it will also be parsed here.
*----------
*/
static void
dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name, const char *subname,
const char *tag, const char *nspname, const char *owner,
- const char *acls)
+ const char *acls, const char *racls,
+ const char *initacls, const char *initracls)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer sql;
@@ -13836,11 +14497,30 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
sql = createPQExpBuffer();
- if (!buildACLCommands(name, subname, type, acls, owner,
+ /*
+ * Check to see if this object has had any initial ACLs included for it.
+ * If so, we are in binary upgrade mode and these are the ACLs to turn
+ * into GRANT and REVOKE statements to set and record the initial
+ * privileges for an extension object. Let the backend know that these
+ * are to be recorded by calling binary_upgrade_set_record_init_privs()
+ * before and after.
+ */
+ if (strlen(initacls) != 0 || strlen(initracls) != 0)
+ {
+ appendPQExpBuffer(sql, "SELECT binary_upgrade_set_record_init_privs(true);\n");
+ if (!buildACLCommands(name, subname, type, initacls, initracls, owner,
+ "", fout->remoteVersion, sql))
+ exit_horribly(NULL,
+ "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+ initacls, initracls, name, type);
+ appendPQExpBuffer(sql, "SELECT binary_upgrade_set_record_init_privs(false);\n");
+ }
+
+ if (!buildACLCommands(name, subname, type, acls, racls, owner,
"", fout->remoteVersion, sql))
exit_horribly(NULL,
- "could not parse ACL list (%s) for object \"%s\" (%s)\n",
- acls, name, type);
+ "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+ acls, racls, name, type);
if (sql->len > 0)
ArchiveEntry(fout, nilCatalogId, createDumpId(),
@@ -14163,7 +14843,8 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
static void
dumpTable(Archive *fout, TableInfo *tbinfo)
{
- char *namecopy;
+ DumpOptions *dopt = fout->dopt;
+ char *namecopy;
if (tbinfo->relkind == RELKIND_SEQUENCE)
dumpSequence(fout, tbinfo);
@@ -14178,12 +14859,13 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
"TABLE",
namecopy, NULL, tbinfo->dobj.name,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->relacl);
+ tbinfo->relacl, tbinfo->rrelacl,
+ tbinfo->initrelacl, tbinfo->initrrelacl);
/*
- * Handle column ACLs, if any. Note: we pull these with a separate
- * query rather than trying to fetch them during getTableAttrs, so
- * that we won't miss ACLs on system columns.
+ * Handle column ACLs, if any. Note: we pull these with a separate query
+ * rather than trying to fetch them during getTableAttrs, so that we won't
+ * miss ACLs on system columns.
*/
if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
{
@@ -14191,18 +14873,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
PGresult *res;
int i;
- appendPQExpBuffer(query,
- "SELECT attname, attacl FROM pg_catalog.pg_attribute "
- "WHERE attrelid = '%u' AND NOT attisdropped "
- "AND attacl IS NOT NULL "
- "ORDER BY attnum",
- tbinfo->dobj.catId.oid);
+ if (fout->remoteVersion >= 90600)
+ {
+ PQExpBuffer acl_subquery = createPQExpBuffer();
+ PQExpBuffer racl_subquery = createPQExpBuffer();
+ PQExpBuffer initacl_subquery = createPQExpBuffer();
+ PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+ buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+ initracl_subquery, "at.attacl", "c.relowner", "'c'",
+ dopt->binary_upgrade);
+
+ appendPQExpBuffer(query,
+ "SELECT at.attname, "
+ "%s AS attacl, "
+ "%s AS rattacl, "
+ "%s AS initattacl, "
+ "%s AS initrattacl "
+ "FROM pg_catalog.pg_attribute at "
+ "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+ "LEFT JOIN pg_init_privs pip ON "
+ "(pip.classoid = "
+ "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+ " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
+ "WHERE at.attrelid = '%u' AND "
+ "NOT at.attisdropped "
+ "AND at.attacl IS NOT NULL "
+ "ORDER BY at.attnum",
+ acl_subquery->data,
+ racl_subquery->data,
+ initacl_subquery->data,
+ initracl_subquery->data,
+ tbinfo->dobj.catId.oid);
+
+ destroyPQExpBuffer(acl_subquery);
+ destroyPQExpBuffer(racl_subquery);
+ destroyPQExpBuffer(initacl_subquery);
+ destroyPQExpBuffer(initracl_subquery);
+ }
+ else
+ {
+ appendPQExpBuffer(query,
+ "SELECT attname, attacl, NULL as rattacl, "
+ "NULL AS initattacl, NULL AS initrattacl "
+ "FROM pg_catalog.pg_attribute "
+ "WHERE attrelid = '%u' AND NOT attisdropped "
+ "AND attacl IS NOT NULL "
+ "ORDER BY attnum",
+ tbinfo->dobj.catId.oid);
+ }
+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < PQntuples(res); i++)
{
char *attname = PQgetvalue(res, i, 0);
char *attacl = PQgetvalue(res, i, 1);
+ char *rattacl = PQgetvalue(res, i, 2);
+ char *initattacl = PQgetvalue(res, i, 3);
+ char *initrattacl = PQgetvalue(res, i, 4);
char *attnamecopy;
char *acltag;
@@ -14212,7 +14941,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
namecopy, attnamecopy, acltag,
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- attacl);
+ attacl, rattacl, initattacl, initrattacl);
free(attnamecopy);
free(acltag);
}
@@ -14909,7 +15638,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
(strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
reltypename,
tbinfo->postponed_def ?
- SECTION_POST_DATA : SECTION_PRE_DATA,
+ SECTION_POST_DATA : SECTION_PRE_DATA,
q->data, delq->data, NULL,
NULL, 0,
NULL, NULL);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 85f9f480ba5..7314cbeec80 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -113,6 +113,9 @@ typedef struct _namespaceInfo
DumpableObject dobj;
char *rolname; /* name of owner, or empty string */
char *nspacl;
+ char *rnspacl;
+ char *initnspacl;
+ char *initrnspacl;
} NamespaceInfo;
typedef struct _extensionInfo
@@ -135,6 +138,9 @@ typedef struct _typeInfo
*/
char *rolname; /* name of owner, or empty string */
char *typacl;
+ char *rtypacl;
+ char *inittypacl;
+ char *initrtypacl;
Oid typelem;
Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */
@@ -164,6 +170,9 @@ typedef struct _funcInfo
Oid *argtypes;
Oid prorettype;
char *proacl;
+ char *rproacl;
+ char *initproacl;
+ char *initrproacl;
} FuncInfo;
/* AggInfo is a superset of FuncInfo */
@@ -220,6 +229,9 @@ typedef struct _tableInfo
DumpableObject dobj;
char *rolname; /* name of owner, or empty string */
char *relacl;
+ char *rrelacl;
+ char *initrelacl;
+ char *initrrelacl;
char relkind;
char relpersistence; /* relation persistence */
bool relispopulated; /* relation is populated */
@@ -388,6 +400,9 @@ typedef struct _procLangInfo
Oid laninline;
Oid lanvalidator;
char *lanacl;
+ char *rlanacl;
+ char *initlanacl;
+ char *initrlanacl;
char *lanowner; /* name of owner, or empty string */
} ProcLangInfo;
@@ -457,6 +472,9 @@ typedef struct _fdwInfo
char *fdwvalidator;
char *fdwoptions;
char *fdwacl;
+ char *rfdwacl;
+ char *initfdwacl;
+ char *initrfdwacl;
} FdwInfo;
typedef struct _foreignServerInfo
@@ -467,6 +485,9 @@ typedef struct _foreignServerInfo
char *srvtype;
char *srvversion;
char *srvacl;
+ char *rsrvacl;
+ char *initsrvacl;
+ char *initrsrvacl;
char *srvoptions;
} ForeignServerInfo;
@@ -483,6 +504,9 @@ typedef struct _blobInfo
DumpableObject dobj;
char *rolname;
char *blobacl;
+ char *rblobacl;
+ char *initblobacl;
+ char *initrblobacl;
} BlobInfo;
/*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 530d3f4d2c0..a59493710b2 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1113,8 +1113,8 @@ dumpTablespaces(PGconn *conn)
fspcname, spcoptions);
if (!skip_acls &&
- !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
- "", server_version, buf))
+ !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, "",
+ spcowner, "", server_version, buf))
{
fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
progname, spcacl, fspcname);
@@ -1444,7 +1444,7 @@ dumpCreateDB(PGconn *conn)
}
if (!skip_acls &&
- !buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
+ !buildACLCommands(fdbname, NULL, "DATABASE", dbacl, "", dbowner,
"", server_version, buf))
{
fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h
index e7da4138717..709373c8f89 100644
--- a/src/include/catalog/binary_upgrade.h
+++ b/src/include/catalog/binary_upgrade.h
@@ -30,4 +30,6 @@ extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_class_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_pg_authid_oid;
+extern PGDLLIMPORT bool binary_upgrade_record_init_privs;
+
#endif /* BINARY_UPGRADE_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 36635f81305..d7dbc739280 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5245,6 +5245,8 @@ DATA(insert OID = 3590 ( binary_upgrade_set_next_pg_authid_oid PGNSP PGUID 12 1
DESCR("for use by pg_upgrade");
DATA(insert OID = 3591 ( binary_upgrade_create_empty_extension PGNSP PGUID 12 1 0 0 0 f f f f f f v r 7 0 2278 "25 25 16 25 1028 1009 1009" _null_ _null_ _null_ _null_ _null_ binary_upgrade_create_empty_extension _null_ _null_ _null_ ));
DESCR("for use by pg_upgrade");
+DATA(insert OID = 4083 ( binary_upgrade_set_record_init_privs PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 2278 "16" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_record_init_privs _null_ _null_ _null_ ));
+DESCR("for use by pg_upgrade");
/* replication/origin.h */
DATA(insert OID = 6003 ( pg_replication_origin_create PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "25" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_create _null_ _null_ _null_ ));
diff --git a/src/test/regress/expected/init_privs.out b/src/test/regress/expected/init_privs.out
new file mode 100644
index 00000000000..980940fa67f
--- /dev/null
+++ b/src/test/regress/expected/init_privs.out
@@ -0,0 +1,13 @@
+-- Test iniital privileges
+-- There should always be some initial privileges, set up by initdb
+SELECT count(*) > 0 FROM pg_init_privs;
+ ?column?
+----------
+ t
+(1 row)
+
+CREATE ROLE init_privs_test_role1;
+CREATE ROLE init_privs_test_role2;
+-- Intentionally include some non-initial privs for pg_dump to dump out
+GRANT SELECT ON pg_proc TO init_privs_test_role1;
+GRANT SELECT (prosrc) ON pg_proc TO init_privs_test_role2;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7c7b58d43d9..6c1f21bb627 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: select_into select_distinct select_distinct_on select_implicit select_havi
# ----------
# Another group of parallel tests
# ----------
-test: brin gin gist spgist privileges security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator
+test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 1b66516a13f..8269c524dc6 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -105,6 +105,7 @@ test: gin
test: gist
test: spgist
test: privileges
+test: init_privs
test: security_label
test: collate
test: matview
diff --git a/src/test/regress/sql/init_privs.sql b/src/test/regress/sql/init_privs.sql
new file mode 100644
index 00000000000..38d4a885389
--- /dev/null
+++ b/src/test/regress/sql/init_privs.sql
@@ -0,0 +1,11 @@
+-- Test iniital privileges
+
+-- There should always be some initial privileges, set up by initdb
+SELECT count(*) > 0 FROM pg_init_privs;
+
+CREATE ROLE init_privs_test_role1;
+CREATE ROLE init_privs_test_role2;
+
+-- Intentionally include some non-initial privs for pg_dump to dump out
+GRANT SELECT ON pg_proc TO init_privs_test_role1;
+GRANT SELECT (prosrc) ON pg_proc TO init_privs_test_role2;