aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/aclchk.c29
-rw-r--r--src/backend/catalog/heap.c15
-rw-r--r--src/backend/catalog/pg_namespace.c3
-rw-r--r--src/backend/catalog/pg_proc.c14
-rw-r--r--src/backend/catalog/pg_type.c163
-rw-r--r--src/backend/commands/typecmds.c33
-rw-r--r--src/include/catalog/pg_type.h22
-rw-r--r--src/include/utils/acl.h2
-rw-r--r--src/test/regress/expected/privileges.out7
-rw-r--r--src/test/regress/sql/privileges.sql9
10 files changed, 160 insertions, 137 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 578e4c65927..bd147752ef9 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -5445,7 +5445,10 @@ get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
/*
* Get default permissions for newly created object within given schema
*
- * Returns NULL if built-in system defaults should be used
+ * Returns NULL if built-in system defaults should be used.
+ *
+ * If the result is not NULL, caller must call recordDependencyOnNewAcl
+ * once the OID of the new object is known.
*/
Acl *
get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
@@ -5521,6 +5524,30 @@ get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
}
/*
+ * Record dependencies on roles mentioned in a new object's ACL.
+ */
+void
+recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
+ Oid ownerId, Acl *acl)
+{
+ int nmembers;
+ Oid *members;
+
+ /* Nothing to do if ACL is defaulted */
+ if (acl == NULL)
+ return;
+
+ /* Extract roles mentioned in ACL */
+ nmembers = aclmembers(acl, &members);
+
+ /* Update the shared dependency ACL info */
+ updateAclDependencies(classId, objectId, objsubId,
+ ownerId,
+ 0, NULL,
+ nmembers, members);
+}
+
+/*
* Record initial privileges for the top-level object passed in.
*
* For the object passed in, this will record its ACL (if any) and the ACLs of
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 7203c86c4d4..bd4c439ef35 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1375,6 +1375,7 @@ heap_create_with_catalog(const char *relname,
myself.classId = RelationRelationId;
myself.objectId = relid;
myself.objectSubId = 0;
+
referenced.classId = NamespaceRelationId;
referenced.objectId = relnamespace;
referenced.objectSubId = 0;
@@ -1382,6 +1383,8 @@ heap_create_with_catalog(const char *relname,
recordDependencyOnOwner(RelationRelationId, relid, ownerid);
+ recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
+
recordDependencyOnCurrentExtension(&myself, false);
if (reloftypeid)
@@ -1391,18 +1394,6 @@ heap_create_with_catalog(const char *relname,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
-
- if (relacl != NULL)
- {
- int nnewmembers;
- Oid *newmembers;
-
- nnewmembers = aclmembers(relacl, &newmembers);
- updateAclDependencies(RelationRelationId, relid, 0,
- ownerid,
- 0, NULL,
- nnewmembers, newmembers);
- }
}
/* Post creation hook for new relation */
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 2cf52be0255..0538e31b3b3 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -100,6 +100,9 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
/* dependency on owner */
recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
+ /* dependences on roles mentioned in default ACL */
+ recordDependencyOnNewAcl(NamespaceRelationId, nspoid, 0, ownerId, nspacl);
+
/* dependency on extension ... but not for magic temp schemas */
if (!isTemp)
recordDependencyOnCurrentExtension(&myself, false);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 0c817047cd1..e367da7dba5 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -654,17 +654,9 @@ ProcedureCreate(const char *procedureName,
recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
/* dependency on any roles mentioned in ACL */
- if (!is_update && proacl != NULL)
- {
- int nnewmembers;
- Oid *newmembers;
-
- nnewmembers = aclmembers(proacl, &newmembers);
- updateAclDependencies(ProcedureRelationId, retval, 0,
- proowner,
- 0, NULL,
- nnewmembers, newmembers);
- }
+ if (!is_update)
+ recordDependencyOnNewAcl(ProcedureRelationId, retval, 0,
+ proowner, proacl);
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, is_update);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 2ddd46d48ed..b729e7ec95d 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -147,23 +147,13 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
* Create dependencies. We can/must skip this in bootstrap mode.
*/
if (!IsBootstrapProcessingMode())
- GenerateTypeDependencies(typeNamespace,
- typoid,
- InvalidOid,
+ GenerateTypeDependencies(typoid,
+ (Form_pg_type) GETSTRUCT(tup),
+ NULL,
+ NULL,
0,
- ownerId,
- F_SHELL_IN,
- F_SHELL_OUT,
- InvalidOid,
- InvalidOid,
- InvalidOid,
- InvalidOid,
- InvalidOid,
- InvalidOid,
false,
- InvalidOid,
- InvalidOid,
- NULL,
+ false,
false);
/* Post creation hook for new shell type */
@@ -225,14 +215,15 @@ TypeCreate(Oid newTypeOid,
{
Relation pg_type_desc;
Oid typeObjectId;
+ bool isDependentType;
bool rebuildDeps = false;
+ Acl *typacl;
HeapTuple tup;
bool nulls[Natts_pg_type];
bool replaces[Natts_pg_type];
Datum values[Natts_pg_type];
NameData name;
int i;
- Acl *typacl = NULL;
ObjectAddress address;
/*
@@ -321,6 +312,17 @@ TypeCreate(Oid newTypeOid,
errmsg("fixed-size types must have storage PLAIN")));
/*
+ * This is a dependent type if it's an implicitly-created array type, or
+ * if it's a relation rowtype that's not a composite type. For such types
+ * we'll leave the ACL empty, and we'll skip creating some dependency
+ * records because there will be a dependency already through the
+ * depended-on type or relation. (Caution: this is closely intertwined
+ * with some behavior in GenerateTypeDependencies.)
+ */
+ isDependentType = isImplicitArray ||
+ (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
+
+ /*
* initialize arrays needed for heap_form_tuple or heap_modify_tuple
*/
for (i = 0; i < Natts_pg_type; ++i)
@@ -379,8 +381,14 @@ TypeCreate(Oid newTypeOid,
else
nulls[Anum_pg_type_typdefault - 1] = true;
- typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
- typeNamespace);
+ /*
+ * Initialize the type's ACL, too. But dependent types don't get one.
+ */
+ if (isDependentType)
+ typacl = NULL;
+ else
+ typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
+ typeNamespace);
if (typacl != NULL)
values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
else
@@ -462,25 +470,15 @@ TypeCreate(Oid newTypeOid,
* Create dependencies. We can/must skip this in bootstrap mode.
*/
if (!IsBootstrapProcessingMode())
- GenerateTypeDependencies(typeNamespace,
- typeObjectId,
- relationOid,
- relationKind,
- ownerId,
- inputProcedure,
- outputProcedure,
- receiveProcedure,
- sendProcedure,
- typmodinProcedure,
- typmodoutProcedure,
- analyzeProcedure,
- elementType,
- isImplicitArray,
- baseType,
- typeCollation,
+ GenerateTypeDependencies(typeObjectId,
+ (Form_pg_type) GETSTRUCT(tup),
(defaultTypeBin ?
stringToNode(defaultTypeBin) :
NULL),
+ typacl,
+ relationKind,
+ isImplicitArray,
+ isDependentType,
rebuildDeps);
/* Post creation hook for new type */
@@ -499,6 +497,17 @@ TypeCreate(Oid newTypeOid,
/*
* GenerateTypeDependencies: build the dependencies needed for a type
*
+ * Most of what this function needs to know about the type is passed as the
+ * new pg_type row, typeForm. But we can't get at the varlena fields through
+ * that, so defaultExpr and typacl are passed separately. (typacl is really
+ * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
+ *
+ * relationKind and isImplicitArray aren't visible in the pg_type row either,
+ * so they're also passed separately.
+ *
+ * isDependentType is true if this is an implicit array or relation rowtype;
+ * that means it doesn't need its own dependencies on owner etc.
+ *
* If rebuild is true, we remove existing dependencies and rebuild them
* from scratch. This is needed for ALTER TYPE, and also when replacing
* a shell type. We don't remove an existing extension dependency, though.
@@ -508,23 +517,13 @@ TypeCreate(Oid newTypeOid,
* that type will become a member of the extension.)
*/
void
-GenerateTypeDependencies(Oid typeNamespace,
- Oid typeObjectId,
- Oid relationOid, /* only for relation rowtypes */
- char relationKind, /* ditto */
- Oid owner,
- Oid inputProcedure,
- Oid outputProcedure,
- Oid receiveProcedure,
- Oid sendProcedure,
- Oid typmodinProcedure,
- Oid typmodoutProcedure,
- Oid analyzeProcedure,
- Oid elementType,
- bool isImplicitArray,
- Oid baseType,
- Oid typeCollation,
+GenerateTypeDependencies(Oid typeObjectId,
+ Form_pg_type typeForm,
Node *defaultExpr,
+ void *typacl,
+ char relationKind, /* only for relation rowtypes */
+ bool isImplicitArray,
+ bool isDependentType,
bool rebuild)
{
ObjectAddress myself,
@@ -542,79 +541,80 @@ GenerateTypeDependencies(Oid typeNamespace,
myself.objectSubId = 0;
/*
- * Make dependencies on namespace, owner, extension.
+ * Make dependencies on namespace, owner, ACL, extension.
*
- * For a relation rowtype (that's not a composite type), we should skip
- * these because we'll depend on them indirectly through the pg_class
- * entry. Likewise, skip for implicit arrays since we'll depend on them
- * through the element type.
+ * Skip these for a dependent type, since it will have such dependencies
+ * indirectly through its depended-on type or relation.
*/
- if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
- !isImplicitArray)
+ if (!isDependentType)
{
referenced.classId = NamespaceRelationId;
- referenced.objectId = typeNamespace;
+ referenced.objectId = typeForm->typnamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
- recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
+ recordDependencyOnOwner(TypeRelationId, typeObjectId,
+ typeForm->typowner);
+
+ recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
+ typeForm->typowner, typacl);
recordDependencyOnCurrentExtension(&myself, rebuild);
}
/* Normal dependencies on the I/O functions */
- if (OidIsValid(inputProcedure))
+ if (OidIsValid(typeForm->typinput))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = inputProcedure;
+ referenced.objectId = typeForm->typinput;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(outputProcedure))
+ if (OidIsValid(typeForm->typoutput))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = outputProcedure;
+ referenced.objectId = typeForm->typoutput;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(receiveProcedure))
+ if (OidIsValid(typeForm->typreceive))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = receiveProcedure;
+ referenced.objectId = typeForm->typreceive;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(sendProcedure))
+ if (OidIsValid(typeForm->typsend))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = sendProcedure;
+ referenced.objectId = typeForm->typsend;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(typmodinProcedure))
+ if (OidIsValid(typeForm->typmodin))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = typmodinProcedure;
+ referenced.objectId = typeForm->typmodin;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(typmodoutProcedure))
+ if (OidIsValid(typeForm->typmodout))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = typmodoutProcedure;
+ referenced.objectId = typeForm->typmodout;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- if (OidIsValid(analyzeProcedure))
+ if (OidIsValid(typeForm->typanalyze))
{
referenced.classId = ProcedureRelationId;
- referenced.objectId = analyzeProcedure;
+ referenced.objectId = typeForm->typanalyze;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -628,10 +628,10 @@ GenerateTypeDependencies(Oid typeNamespace,
* relation is, and not otherwise. And in the latter, of course we get the
* opposite effect.
*/
- if (OidIsValid(relationOid))
+ if (OidIsValid(typeForm->typrelid))
{
referenced.classId = RelationRelationId;
- referenced.objectId = relationOid;
+ referenced.objectId = typeForm->typrelid;
referenced.objectSubId = 0;
if (relationKind != RELKIND_COMPOSITE_TYPE)
@@ -645,30 +645,31 @@ GenerateTypeDependencies(Oid typeNamespace,
* dependent on the element type. Otherwise, if it has an element type,
* the dependency is a normal one.
*/
- if (OidIsValid(elementType))
+ if (OidIsValid(typeForm->typelem))
{
referenced.classId = TypeRelationId;
- referenced.objectId = elementType;
+ referenced.objectId = typeForm->typelem;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced,
isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
}
/* Normal dependency from a domain to its base type. */
- if (OidIsValid(baseType))
+ if (OidIsValid(typeForm->typbasetype))
{
referenced.classId = TypeRelationId;
- referenced.objectId = baseType;
+ referenced.objectId = typeForm->typbasetype;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Normal dependency from a domain to its collation. */
/* We know the default collation is pinned, so don't bother recording it */
- if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
+ if (OidIsValid(typeForm->typcollation) &&
+ typeForm->typcollation != DEFAULT_COLLATION_OID)
{
referenced.classId = CollationRelationId;
- referenced.objectId = typeCollation;
+ referenced.objectId = typeForm->typcollation;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 12388004d98..66f7c577267 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2179,6 +2179,9 @@ AlterDomainDefault(List *names, Node *defaultRaw)
Relation rel;
char *defaultValue;
Node *defaultExpr = NULL; /* NULL if no default specified */
+ Acl *typacl;
+ Datum aclDatum;
+ bool isNull;
Datum new_record[Natts_pg_type];
bool new_record_nulls[Natts_pg_type];
bool new_record_repl[Natts_pg_type];
@@ -2270,25 +2273,23 @@ AlterDomainDefault(List *names, Node *defaultRaw)
CatalogTupleUpdate(rel, &tup->t_self, newtuple);
+ /* Must extract ACL for use of GenerateTypeDependencies */
+ aclDatum = heap_getattr(newtuple, Anum_pg_type_typacl,
+ RelationGetDescr(rel), &isNull);
+ if (isNull)
+ typacl = NULL;
+ else
+ typacl = DatumGetAclPCopy(aclDatum);
+
/* Rebuild dependencies */
- GenerateTypeDependencies(typTup->typnamespace,
- domainoid,
- InvalidOid, /* typrelid is n/a */
+ GenerateTypeDependencies(domainoid,
+ (Form_pg_type) GETSTRUCT(newtuple),
+ defaultExpr,
+ typacl,
0, /* relation kind is n/a */
- typTup->typowner,
- typTup->typinput,
- typTup->typoutput,
- typTup->typreceive,
- typTup->typsend,
- typTup->typmodin,
- typTup->typmodout,
- typTup->typanalyze,
- InvalidOid,
false, /* a domain isn't an implicit array */
- typTup->typbasetype,
- typTup->typcollation,
- defaultExpr,
- true); /* Rebuild is true */
+ false, /* nor is it any kind of dependent type */
+ true); /* We do need to rebuild dependencies */
InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 76f3297e1d9..87c9b673cf4 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -323,23 +323,13 @@ extern ObjectAddress TypeCreate(Oid newTypeOid,
bool typeNotNull,
Oid typeCollation);
-extern void GenerateTypeDependencies(Oid typeNamespace,
- Oid typeObjectId,
- Oid relationOid,
- char relationKind,
- Oid owner,
- Oid inputProcedure,
- Oid outputProcedure,
- Oid receiveProcedure,
- Oid sendProcedure,
- Oid typmodinProcedure,
- Oid typmodoutProcedure,
- Oid analyzeProcedure,
- Oid elementType,
- bool isImplicitArray,
- Oid baseType,
- Oid typeCollation,
+extern void GenerateTypeDependencies(Oid typeObjectId,
+ Form_pg_type typeForm,
Node *defaultExpr,
+ void *typacl,
+ char relationKind, /* only for relation rowtypes */
+ bool isImplicitArray,
+ bool isDependentType,
bool rebuild);
extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index f4d4be8d0d3..72936eeb4d7 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -189,6 +189,8 @@ typedef enum
extern Acl *acldefault(ObjectType objtype, Oid ownerId);
extern Acl *get_user_default_acl(ObjectType objtype, Oid ownerId,
Oid nsp_oid);
+extern void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
+ Oid ownerId, Acl *acl);
extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,
int modechg, Oid ownerId, DropBehavior behavior);
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index d3925e75f5d..3af92ed1a83 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1571,6 +1571,12 @@ SELECT has_table_privilege('regress_priv_user1', 'testns.acltest1', 'INSERT'); -
ALTER DEFAULT PRIVILEGES FOR ROLE regress_priv_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_priv_user2; -- error
ERROR: cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS
+--
+-- Testing blanket default grants is very hazardous since it might change
+-- the privileges attached to objects created by concurrent regression tests.
+-- To avoid that, be sure to revoke the privileges again before committing.
+--
+BEGIN;
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_priv_user2;
CREATE SCHEMA testns2;
SELECT has_schema_privilege('regress_priv_user2', 'testns2', 'USAGE'); -- yes
@@ -1614,6 +1620,7 @@ SELECT has_schema_privilege('regress_priv_user2', 'testns4', 'CREATE'); -- yes
(1 row)
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_priv_user2;
+COMMIT;
CREATE SCHEMA testns5;
SELECT has_schema_privilege('regress_priv_user2', 'testns5', 'USAGE'); -- no
has_schema_privilege
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 0d5c2cac243..e3e69302a25 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -935,6 +935,13 @@ ALTER DEFAULT PRIVILEGES FOR ROLE regress_priv_user1 REVOKE EXECUTE ON FUNCTIONS
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_priv_user2; -- error
+--
+-- Testing blanket default grants is very hazardous since it might change
+-- the privileges attached to objects created by concurrent regression tests.
+-- To avoid that, be sure to revoke the privileges again before committing.
+--
+BEGIN;
+
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_priv_user2;
CREATE SCHEMA testns2;
@@ -958,6 +965,8 @@ SELECT has_schema_privilege('regress_priv_user2', 'testns4', 'CREATE'); -- yes
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_priv_user2;
+COMMIT;
+
CREATE SCHEMA testns5;
SELECT has_schema_privilege('regress_priv_user2', 'testns5', 'USAGE'); -- no