diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml index 4f0b0bc9c837277b393a0dec5a40b0c67a9e1ca5..2099c3471ece73b707b38fbdc03021d4d7549041 100644 --- a/doc/src/sgml/ref/alter_default_privileges.sgml +++ b/doc/src/sgml/ref/alter_default_privileges.sgml @@ -1,5 +1,5 @@ @@ -150,9 +150,10 @@ REVOKE [ GRANT OPTION FOR ] - If you wish to drop a role for which the default privileges have ever been - altered, it is necessary to use DROP OWNED BY first, - to get rid of the default privileges entry for the role. + If you wish to drop a role for which the default privileges have been + altered, it is necessary to reverse the changes in its default privileges + or use DROP OWNED BY to get rid of the default privileges entry + for the role. diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index f61add142aaa2e36d4b10bb811b5fd58e9f5d400..025898d1a5aeadfa0e5adfcff0df4070a67ae35d 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.165 2010/04/05 01:09:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.166 2010/04/05 01:58:03 tgl Exp $ * * NOTES * See acl.h. @@ -1072,6 +1072,7 @@ SetDefaultACL(InternalDefaultACL *iacls) Relation rel; HeapTuple tuple; bool isNew; + Acl *def_acl; Acl *old_acl; Acl *new_acl; HeapTuple newtuple; @@ -1085,6 +1086,17 @@ SetDefaultACL(InternalDefaultACL *iacls) rel = heap_open(DefaultAclRelationId, RowExclusiveLock); + /* + * The default for a global entry is the hard-wired default ACL for the + * particular object type. The default for non-global entries is an empty + * ACL. This must be so because global entries replace the hard-wired + * defaults, while others are added on. + */ + if (!OidIsValid(iacls->nspid)) + def_acl = acldefault(iacls->objtype, iacls->roleid); + else + def_acl = make_empty_acl(); + /* * Convert ACL object type to pg_default_acl object type and handle * all_privs option @@ -1133,7 +1145,7 @@ SetDefaultACL(InternalDefaultACL *iacls) if (!isNull) old_acl = DatumGetAclPCopy(aclDatum); else - old_acl = NULL; + old_acl = NULL; /* this case shouldn't happen, probably */ isNew = false; } else @@ -1153,17 +1165,8 @@ SetDefaultACL(InternalDefaultACL *iacls) } else { - /* - * If we are creating a global entry, start with the hard-wired - * defaults and modify as per command. Otherwise, start with an empty - * ACL and modify that. This is needed because global entries replace - * the hard-wired defaults, while others do not. - */ - if (!OidIsValid(iacls->nspid)) - old_acl = acldefault(iacls->objtype, iacls->roleid); - else - old_acl = make_empty_acl(); - + /* If no or null entry, start with the default ACL value */ + old_acl = aclcopy(def_acl); /* There are no old member roles according to the catalogs */ noldmembers = 0; oldmembers = NULL; @@ -1182,71 +1185,101 @@ SetDefaultACL(InternalDefaultACL *iacls) iacls->roleid, iacls->roleid); - /* finished building new ACL value, now insert it */ - MemSet(values, 0, sizeof(values)); - MemSet(nulls, false, sizeof(nulls)); - MemSet(replaces, false, sizeof(replaces)); - - if (isNew) + /* + * If the result is the same as the default value, we do not need an + * explicit pg_default_acl entry, and should in fact remove the entry + * if it exists. Must sort both arrays to compare properly. + */ + aclitemsort(new_acl); + aclitemsort(def_acl); + if (aclequal(new_acl, def_acl)) { - values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid); - values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid); - values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype); - values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + /* delete old entry, if indeed there is one */ + if (!isNew) + { + ObjectAddress myself; - newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); - simple_heap_insert(rel, newtuple); + /* + * The dependency machinery will take care of removing all + * associated dependency entries. We use DROP_RESTRICT since + * there shouldn't be anything depending on this entry. + */ + myself.classId = DefaultAclRelationId; + myself.objectId = HeapTupleGetOid(tuple); + myself.objectSubId = 0; + + performDeletion(&myself, DROP_RESTRICT); + } } else { - values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_default_acl_defaclacl - 1] = true; + /* Prepare to insert or update pg_default_acl entry */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - values, nulls, replaces); - simple_heap_update(rel, &newtuple->t_self, newtuple); - } + if (isNew) + { + /* insert new entry */ + values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid); + values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid); + values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype); + values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); + simple_heap_insert(rel, newtuple); + } + else + { + /* update existing entry */ + values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + replaces[Anum_pg_default_acl_defaclacl - 1] = true; - /* keep the catalog indexes up to date */ - CatalogUpdateIndexes(rel, newtuple); + newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + values, nulls, replaces); + simple_heap_update(rel, &newtuple->t_self, newtuple); + } - /* these dependencies don't change in an update */ - if (isNew) - { - /* dependency on role */ - recordDependencyOnOwner(DefaultAclRelationId, - HeapTupleGetOid(newtuple), - iacls->roleid); + /* keep the catalog indexes up to date */ + CatalogUpdateIndexes(rel, newtuple); - /* dependency on namespace */ - if (OidIsValid(iacls->nspid)) + /* these dependencies don't change in an update */ + if (isNew) { - ObjectAddress myself, - referenced; + /* dependency on role */ + recordDependencyOnOwner(DefaultAclRelationId, + HeapTupleGetOid(newtuple), + iacls->roleid); - myself.classId = DefaultAclRelationId; - myself.objectId = HeapTupleGetOid(newtuple); - myself.objectSubId = 0; + /* dependency on namespace */ + if (OidIsValid(iacls->nspid)) + { + ObjectAddress myself, + referenced; - referenced.classId = NamespaceRelationId; - referenced.objectId = iacls->nspid; - referenced.objectSubId = 0; + myself.classId = DefaultAclRelationId; + myself.objectId = HeapTupleGetOid(newtuple); + myself.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); - } - } + referenced.classId = NamespaceRelationId; + referenced.objectId = iacls->nspid; + referenced.objectSubId = 0; - /* - * Update the shared dependency ACL info - */ - nnewmembers = aclmembers(new_acl, &newmembers); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + } + } - updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0, - iacls->roleid, - noldmembers, oldmembers, - nnewmembers, newmembers); + /* + * Update the shared dependency ACL info + */ + nnewmembers = aclmembers(new_acl, &newmembers); - pfree(new_acl); + updateAclDependencies(DefaultAclRelationId, + HeapTupleGetOid(newtuple), 0, + iacls->roleid, + noldmembers, oldmembers, + nnewmembers, newmembers); + } if (HeapTupleIsValid(tuple)) ReleaseSysCache(tuple);