diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 066b7fdb740..9c8711ed050 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -5158,7 +5158,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(GrantObjectType objtype, Oid ownerId, Oid nsp_oid) @@ -5229,6 +5232,30 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid) return result; } +/* + * 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. * diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 68e504ced84..f1600fe42f3 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1302,6 +1302,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; @@ -1309,6 +1310,8 @@ heap_create_with_catalog(const char *relname, recordDependencyOnOwner(RelationRelationId, relid, ownerid); + recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl); + if (relpersistence != RELPERSISTENCE_TEMP) recordDependencyOnCurrentExtension(&myself, false); @@ -1319,18 +1322,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_proc.c b/src/backend/catalog/pg_proc.c index c1d1505e648..b39e0d4cbc6 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -671,17 +671,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 525273ef3ec..c88ab9942a9 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -150,23 +150,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, - 0, - ownerId, - F_SHELL_IN, - F_SHELL_OUT, - InvalidOid, - InvalidOid, - InvalidOid, - InvalidOid, - InvalidOid, - InvalidOid, - false, - InvalidOid, - InvalidOid, + GenerateTypeDependencies(typoid, + (Form_pg_type) GETSTRUCT(tup), NULL, + NULL, + 0, + false, + false, false); /* Post creation hook for new shell type */ @@ -228,14 +218,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; /* @@ -323,6 +314,17 @@ TypeCreate(Oid newTypeOid, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), 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 */ @@ -382,8 +384,14 @@ TypeCreate(Oid newTypeOid, else nulls[Anum_pg_type_typdefault - 1] = true; - typacl = get_user_default_acl(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(ACL_OBJECT_TYPE, ownerId, + typeNamespace); if (typacl != NULL) values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl); else @@ -468,25 +476,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 */ @@ -505,6 +503,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. @@ -514,23 +523,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, @@ -548,79 +547,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); } @@ -634,10 +634,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) @@ -651,30 +651,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); + 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 47949a27f14..eef125a5242 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -2138,6 +2138,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]; @@ -2231,25 +2234,23 @@ AlterDomainDefault(List *names, Node *defaultRaw) CatalogUpdateIndexes(rel, 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 */ - 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, + GenerateTypeDependencies(domainoid, + (Form_pg_type) GETSTRUCT(newtuple), defaultExpr, - true); /* Rebuild is true */ + typacl, + 0, /* relation kind is n/a */ + false, /* a domain isn't an implicit array */ + 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_fn.h b/src/include/catalog/pg_type_fn.h index d7bbfdb0120..ff9be8cd747 100644 --- a/src/include/catalog/pg_type_fn.h +++ b/src/include/catalog/pg_type_fn.h @@ -54,23 +54,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 14279f79da0..8ef5cd9603c 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -216,6 +216,8 @@ typedef enum AclObjectKind extern Acl *acldefault(GrantObjectType objtype, Oid ownerId); extern Acl *get_user_default_acl(GrantObjectType 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);