Index: doc/src/sgml/reference.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/reference.sgml,v retrieving revision 1.56 diff -c -r1.56 reference.sgml *** doc/src/sgml/reference.sgml 29 Jul 2005 15:13:11 -0000 1.56 --- doc/src/sgml/reference.sgml 14 Sep 2005 16:43:47 -0000 *************** *** 102,107 **** --- 102,108 ---- &dropLanguage; &dropOperator; &dropOperatorClass; + &dropOwned; &dropRole; &dropRule; &dropSchema; *************** *** 125,130 **** --- 126,132 ---- ¬ify; &prepare; &prepareTransaction; + &reassignOwned; &reindex; &releaseSavepoint; &reset; Index: doc/src/sgml/ref/allfiles.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/allfiles.sgml,v retrieving revision 1.66 diff -c -r1.66 allfiles.sgml *** doc/src/sgml/ref/allfiles.sgml 29 Jul 2005 15:13:11 -0000 1.66 --- doc/src/sgml/ref/allfiles.sgml 13 Sep 2005 21:09:27 -0000 *************** *** 70,75 **** --- 70,76 ---- + *************** *** 93,98 **** --- 94,100 ---- + Index: src/backend/catalog/aclchk.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v retrieving revision 1.120 diff -c -r1.120 aclchk.c *** src/backend/catalog/aclchk.c 15 Oct 2005 02:49:12 -0000 1.120 --- src/backend/catalog/aclchk.c 18 Nov 2005 19:36:04 -0000 *************** *** 17,22 **** --- 17,23 ---- */ #include "postgres.h" + #include "access/genam.h" #include "access/heapam.h" #include "catalog/catalog.h" #include "catalog/dependency.h" *************** *** 41,52 **** #include "utils/syscache.h" ! static void ExecuteGrantStmt_Relation(GrantStmt *stmt); ! static void ExecuteGrantStmt_Database(GrantStmt *stmt); ! static void ExecuteGrantStmt_Function(GrantStmt *stmt); ! static void ExecuteGrantStmt_Language(GrantStmt *stmt); ! static void ExecuteGrantStmt_Namespace(GrantStmt *stmt); ! static void ExecuteGrantStmt_Tablespace(GrantStmt *stmt); static AclMode string_to_privilege(const char *privname); static const char *privilege_to_string(AclMode privilege); --- 42,72 ---- #include "utils/syscache.h" ! static void ExecuteGrantStmt_Relation(GrantStmt *stmt, Oid oid, List *grantees); ! static void ExecuteGrantStmt_Database(GrantStmt *stmt, Oid oid, List *grantees); ! static void ExecuteGrantStmt_Function(GrantStmt *stmt, Oid oid, List *grantees); ! static void ExecuteGrantStmt_Language(GrantStmt *stmt, Oid oid, List *grantees); ! static void ExecuteGrantStmt_Namespace(GrantStmt *stmt, Oid oid, List *grantees); ! static void ExecuteGrantStmt_Tablespace(GrantStmt *stmt, Oid oid, List *grantees); ! ! static void ExecGrant_Relation(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); ! static void ExecGrant_Database(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); ! static void ExecGrant_Function(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); ! static void ExecGrant_Language(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); ! static void ExecGrant_Namespace(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); ! static void ExecGrant_Tablespace(GrantStmt *stmt, Relation relation, ! HeapTuple tuple, AclMode privileges, ! bool all_privs, List *grantees); static AclMode string_to_privilege(const char *privname); static const char *privilege_to_string(AclMode privilege); *************** *** 96,110 **** foreach(j, grantees) { ! PrivGrantee *grantee = (PrivGrantee *) lfirst(j); ! AclItem aclitem; Acl *newer_acl; ! if (grantee->rolname) ! aclitem. ai_grantee = get_roleid_checked(grantee->rolname); ! ! else ! aclitem. ai_grantee = ACL_ID_PUBLIC; /* * Grant options can only be granted to individual roles, not PUBLIC. --- 116,125 ---- foreach(j, grantees) { ! AclItem aclitem; Acl *newer_acl; ! aclitem.ai_grantee = lfirst_oid(j); /* * Grant options can only be granted to individual roles, not PUBLIC. *************** *** 146,175 **** /* ! * Called to execute the utility commands GRANT and REVOKE */ void ! ExecuteGrantStmt(GrantStmt *stmt) { switch (stmt->objtype) { case ACL_OBJECT_RELATION: ! ExecuteGrantStmt_Relation(stmt); break; case ACL_OBJECT_DATABASE: ! ExecuteGrantStmt_Database(stmt); break; case ACL_OBJECT_FUNCTION: ! ExecuteGrantStmt_Function(stmt); break; case ACL_OBJECT_LANGUAGE: ! ExecuteGrantStmt_Language(stmt); break; case ACL_OBJECT_NAMESPACE: ! ExecuteGrantStmt_Namespace(stmt); break; case ACL_OBJECT_TABLESPACE: ! ExecuteGrantStmt_Tablespace(stmt); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", --- 161,224 ---- /* ! * Called to execute the utility commands GRANT and REVOKE. ! * ! * stmt may be a complete GrantStmt created by the parser, or it may be ! * missing the "objects" list and the "grantees" list. In this case, ! * they are taken from the second and third parameters, respectively. */ void ! ExecuteGrantStmt(GrantStmt *stmt, Oid object, Oid grantee) { + List *grantees = NIL; + + /* + * Convert the PrivGrantee list into an Oid list. Note that at this point + * we may insert an ACL_ID_PUBLIC into the list if an empty role name is + * detected, so downstream there shouldn't be any additional work needed to + * support this case. + */ + if (!OidIsValid(grantee)) + { + ListCell *cell; + Assert(stmt->grantees != NIL); + + foreach(cell, stmt->grantees) + { + PrivGrantee *grantee = (PrivGrantee *) lfirst(cell); + + if (grantee->rolname == NULL) + grantees = lappend_oid(grantees, ACL_ID_PUBLIC); + else + grantees = lappend_oid(grantees, + get_roleid_checked(grantee->rolname)); + } + } + else + { + Assert(stmt->grantees == NIL); + grantees = list_make1_oid(grantee); + } + switch (stmt->objtype) { case ACL_OBJECT_RELATION: ! ExecuteGrantStmt_Relation(stmt, object, grantees); break; case ACL_OBJECT_DATABASE: ! ExecuteGrantStmt_Database(stmt, object, grantees); break; case ACL_OBJECT_FUNCTION: ! ExecuteGrantStmt_Function(stmt, object, grantees); break; case ACL_OBJECT_LANGUAGE: ! ExecuteGrantStmt_Language(stmt, object, grantees); break; case ACL_OBJECT_NAMESPACE: ! ExecuteGrantStmt_Namespace(stmt, object, grantees); break; case ACL_OBJECT_TABLESPACE: ! ExecuteGrantStmt_Tablespace(stmt, object, grantees); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", *************** *** 179,189 **** static void ! ExecuteGrantStmt_Relation(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { --- 228,242 ---- static void ! ExecuteGrantStmt_Relation(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; ListCell *i; + Relation relation; + + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); if (stmt->privileges == NIL) { *************** *** 208,261 **** } } ! foreach(i, stmt->objects) { - RangeVar *relvar = (RangeVar *) lfirst(i); - Oid relOid; - Relation relation; HeapTuple tuple; ! Form_pg_class pg_class_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_class]; ! char nulls[Natts_pg_class]; ! char replaces[Natts_pg_class]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! /* open pg_class */ ! relation = heap_open(RelationRelationId, RowExclusiveLock); ! relOid = RangeVarGetRelid(relvar, false); tuple = SearchSysCache(RELOID, ! ObjectIdGetDatum(relOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for relation %u", relOid); pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); /* Not sensible to grant on an index */ if (pg_class_tuple->relkind == RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an index", ! relvar->relname))); /* Composite types aren't tables either */ if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a composite type", ! relvar->relname))); ! /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. --- 261,353 ---- } } ! /* open pg_class */ ! relation = heap_open(RelationRelationId, RowExclusiveLock); ! ! if (stmt->objects) ! { ! Assert(!OidIsValid(object)); ! ! foreach(i, stmt->objects) ! { ! Oid relOid; ! HeapTuple tuple; ! ! RangeVar *relvar = (RangeVar *) lfirst(i); ! relOid = RangeVarGetRelid(relvar, false); ! tuple = SearchSysCache(RELOID, ! ObjectIdGetDatum(relOid), ! 0, 0, 0); ! if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for relation %u", relOid); ! ! ExecGrant_Relation(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! } ! else { HeapTuple tuple; ! ! Assert(stmt->objects == NIL); ! tuple = SearchSysCache(RELOID, ! ObjectIdGetDatum(object), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for relation %u", object); ! ! ExecGrant_Relation(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! ! heap_close(relation, RowExclusiveLock); ! } ! ! static void ! ExecGrant_Relation(GrantStmt *stmt, Relation relation, HeapTuple tuple, ! AclMode privileges, bool all_privs, List *grantees) ! { ! Datum aclDatum; ! Oid relOid; ! Form_pg_class pg_class_tuple; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_class]; ! char nulls[Natts_pg_class]; ! char replaces[Natts_pg_class]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! { pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + relOid = HeapTupleGetOid(tuple); /* Not sensible to grant on an index */ if (pg_class_tuple->relkind == RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an index", ! NameStr(pg_class_tuple->relname)))); /* Composite types aren't tables either */ if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a composite type", ! NameStr(pg_class_tuple->relname)))); /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. *************** *** 285,291 **** ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, ! relvar->relname); } /* --- 377,383 ---- ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, ! NameStr(pg_class_tuple->relname)); } /* *************** *** 330,336 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 422,428 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 356,378 **** noldmembers, oldmembers, nnewmembers, newmembers); - ReleaseSysCache(tuple); - pfree(new_acl); - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Database(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { --- 448,470 ---- noldmembers, oldmembers, nnewmembers, newmembers); pfree(new_acl); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Database(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; ListCell *i; + Relation relation; + + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); if (stmt->privileges == NIL) { *************** *** 397,438 **** } } ! foreach(i, stmt->objects) { - char *dbname = strVal(lfirst(i)); - Relation relation; ScanKeyData entry[1]; ! HeapScanDesc scan; HeapTuple tuple; - Form_pg_database pg_database_tuple; - Datum aclDatum; - bool isNull; - AclMode avail_goptions; - AclMode this_privileges; - Acl *old_acl; - Acl *new_acl; - Oid grantorId; - Oid ownerId; - HeapTuple newtuple; - Datum values[Natts_pg_database]; - char nulls[Natts_pg_database]; - char replaces[Natts_pg_database]; - int noldmembers; - int nnewmembers; - Oid *oldmembers; - Oid *newmembers; - relation = heap_open(DatabaseRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], ! Anum_pg_database_datname, ! BTEqualStrategyNumber, F_NAMEEQ, ! CStringGetDatum(dbname)); ! scan = heap_beginscan(relation, SnapshotNow, 1, entry); ! tuple = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_DATABASE), ! errmsg("database \"%s\" does not exist", dbname))); pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple); /* --- 489,570 ---- } } ! relation = heap_open(DatabaseRelationId, RowExclusiveLock); ! ! if (stmt->objects) ! { ! foreach(i, stmt->objects) ! { ! ScanKeyData entry[1]; ! HeapScanDesc scan; ! HeapTuple tuple; ! char *dbname = strVal(lfirst(i)); ! ! ScanKeyInit(&entry[0], ! Anum_pg_database_datname, ! BTEqualStrategyNumber, F_NAMEEQ, ! CStringGetDatum(dbname)); ! scan = heap_beginscan(relation, SnapshotNow, 1, entry); ! tuple = heap_getnext(scan, ForwardScanDirection); ! if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_DATABASE), ! errmsg("database \"%s\" does not exist", dbname))); ! ! ExecGrant_Database(stmt, relation, tuple, privileges, all_privs, grantees); ! ! heap_endscan(scan); ! } ! } ! else { ScanKeyData entry[1]; ! SysScanDesc scan; HeapTuple tuple; ScanKeyInit(&entry[0], ! ObjectIdAttributeNumber, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(object)); ! scan = systable_beginscan(relation, DatabaseOidIndexId, true, ! SnapshotNow, 1, entry); ! ! tuple = systable_getnext(scan); ! if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "could not find tuple for database %u", object); ! ! ExecGrant_Database(stmt, relation, tuple, privileges, all_privs, grantees); ! ! systable_endscan(scan); ! } ! ! heap_close(relation, RowExclusiveLock); ! } ! ! static void ! ExecGrant_Database(GrantStmt *stmt, Relation relation, HeapTuple tuple, ! AclMode privileges, bool all_privs, List *grantees) ! { ! Form_pg_database pg_database_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_database]; ! char nulls[Natts_pg_database]; ! char replaces[Natts_pg_database]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! { pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple); /* *************** *** 509,515 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 641,647 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 537,557 **** pfree(new_acl); - heap_endscan(scan); - - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Function(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { --- 669,689 ---- pfree(new_acl); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Function(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; ListCell *i; + Relation relation; + + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); if (stmt->privileges == NIL) { *************** *** 576,615 **** } } ! foreach(i, stmt->objects) { ! FuncWithArgs *func = (FuncWithArgs *) lfirst(i); ! Oid oid; ! Relation relation; ! HeapTuple tuple; ! Form_pg_proc pg_proc_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_proc]; ! char nulls[Natts_pg_proc]; ! char replaces[Natts_pg_proc]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false); - relation = heap_open(ProcedureRelationId, RowExclusiveLock); tuple = SearchSysCache(PROCOID, ! ObjectIdGetDatum(oid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for function %u", oid); ! pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. --- 708,780 ---- } } ! relation = heap_open(ProcedureRelationId, RowExclusiveLock); ! ! if (stmt->objects) { ! foreach(i, stmt->objects) ! { ! FuncWithArgs *func = (FuncWithArgs *) lfirst(i); ! Oid funcid; ! HeapTuple tuple; ! ! funcid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false); ! tuple = SearchSysCache(PROCOID, ! ObjectIdGetDatum(funcid), ! 0, 0, 0); ! if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for function %u", funcid); ! ! ExecGrant_Function(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! } ! else ! { ! HeapTuple tuple; tuple = SearchSysCache(PROCOID, ! ObjectIdGetDatum(object), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for function %u", object); ! ! ExecGrant_Function(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! ! heap_close(relation, RowExclusiveLock); ! } + static void + ExecGrant_Function(GrantStmt *stmt, Relation relation, HeapTuple tuple, + AclMode privileges, bool all_privs, List *grantees) + { + Form_pg_proc pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); + Oid funcId; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_proc]; + char nulls[Natts_pg_proc]; + char replaces[Natts_pg_proc]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + { /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. *************** *** 622,627 **** --- 787,794 ---- else old_acl = DatumGetAclPCopy(aclDatum); + funcId = HeapTupleGetOid(tuple); + /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), privileges, old_acl, ownerId, *************** *** 634,640 **** */ if (avail_goptions == ACL_NO_RIGHTS) { ! if (pg_proc_aclmask(oid, grantorId, ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION), ACLMASK_ANY) == ACL_NO_RIGHTS) --- 801,807 ---- */ if (avail_goptions == ACL_NO_RIGHTS) { ! if (pg_proc_aclmask(funcId, grantorId, ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION), ACLMASK_ANY) == ACL_NO_RIGHTS) *************** *** 684,690 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 851,857 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 705,733 **** CatalogUpdateIndexes(relation, newtuple); /* Update the shared dependency ACL info */ ! updateAclDependencies(ProcedureRelationId, oid, ownerId, stmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); - ReleaseSysCache(tuple); - pfree(new_acl); - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Language(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { all_privs = true; --- 872,900 ---- CatalogUpdateIndexes(relation, newtuple); /* Update the shared dependency ACL info */ ! updateAclDependencies(ProcedureRelationId, funcId, ownerId, stmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); pfree(new_acl); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Language(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; + Relation relation; ListCell *i; + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); + if (stmt->privileges == NIL) { all_privs = true; *************** *** 751,794 **** } } ! foreach(i, stmt->objects) { ! char *langname = strVal(lfirst(i)); ! Relation relation; ! HeapTuple tuple; ! Form_pg_language pg_language_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_language]; ! char nulls[Natts_pg_language]; ! char replaces[Natts_pg_language]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! relation = heap_open(LanguageRelationId, RowExclusiveLock); ! tuple = SearchSysCache(LANGNAME, ! PointerGetDatum(langname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_OBJECT), ! errmsg("language \"%s\" does not exist", langname))); ! pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); if (!pg_language_tuple->lanpltrusted) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), ! errmsg("language \"%s\" is not trusted", langname), ! errhint("Only superusers may use untrusted languages."))); /* * Get owner ID and working copy of existing ACL. If there's no ACL, --- 918,995 ---- } } ! relation = heap_open(LanguageRelationId, RowExclusiveLock); ! ! if (stmt->objects) { ! foreach(i, stmt->objects) ! { ! char *langname = strVal(lfirst(i)); ! HeapTuple tuple; ! ! tuple = SearchSysCache(LANGNAME, ! PointerGetDatum(langname), ! 0, 0, 0); ! if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_OBJECT), ! errmsg("language \"%s\" does not exist", langname))); ! ! ExecGrant_Language(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! } ! else ! { ! HeapTuple tuple; ! ! tuple = SearchSysCache(LANGOID, ! ObjectIdGetDatum(object), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for language %u", object); ! ! ExecGrant_Language(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } + heap_close(relation, RowExclusiveLock); + } + + static void + ExecGrant_Language(GrantStmt *stmt, Relation relation, HeapTuple tuple, + AclMode privileges, bool all_privs, List *grantees) + { + Form_pg_language pg_language_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_language]; + char nulls[Natts_pg_language]; + char replaces[Natts_pg_language]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + { + pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); if (!pg_language_tuple->lanpltrusted) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), ! errmsg("language \"%s\" is not trusted", ! NameStr(pg_language_tuple->lanname)), ! errhint("Only superusers may use untrusted languages."))); /* * Get owner ID and working copy of existing ACL. If there's no ACL, *************** *** 867,873 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 1068,1074 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 893,915 **** noldmembers, oldmembers, nnewmembers, newmembers); - ReleaseSysCache(tuple); - pfree(new_acl); - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Namespace(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { --- 1094,1116 ---- noldmembers, oldmembers, nnewmembers, newmembers); pfree(new_acl); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Namespace(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; ListCell *i; + Relation relation; + + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); if (stmt->privileges == NIL) { *************** *** 934,970 **** } } ! foreach(i, stmt->objects) { - char *nspname = strVal(lfirst(i)); - Relation relation; HeapTuple tuple; ! Form_pg_namespace pg_namespace_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_namespace]; ! char nulls[Natts_pg_namespace]; ! char replaces[Natts_pg_namespace]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! relation = heap_open(NamespaceRelationId, RowExclusiveLock); ! tuple = SearchSysCache(NAMESPACENAME, ! CStringGetDatum(nspname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_SCHEMA), ! errmsg("schema \"%s\" does not exist", nspname))); pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); /* --- 1135,1205 ---- } } ! relation = heap_open(NamespaceRelationId, RowExclusiveLock); ! ! if (stmt->objects != NIL) ! { ! foreach (i, stmt->objects) ! { ! HeapTuple tuple; ! char *nspname = strVal(lfirst(i)); ! ! tuple = SearchSysCache(NAMESPACENAME, ! CStringGetDatum(nspname), ! 0, 0, 0); ! if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_SCHEMA), ! errmsg("schema \"%s\" does not exist", nspname))); ! ! ExecGrant_Namespace(stmt, relation, tuple, privileges, ! all_privs, grantees); ! ! ReleaseSysCache(tuple); ! } ! } ! else { HeapTuple tuple; ! ! tuple = SearchSysCache(NAMESPACEOID, ! ObjectIdGetDatum(object), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for namespace %u", object); ! ! ExecGrant_Namespace(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! ReleaseSysCache(tuple); ! } ! ! heap_close(relation, RowExclusiveLock); ! } ! ! static void ! ExecGrant_Namespace(GrantStmt *stmt, Relation relation, HeapTuple tuple, ! AclMode privileges, bool all_privs, List *grantees) ! { ! Form_pg_namespace pg_namespace_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_namespace]; ! char nulls[Natts_pg_namespace]; ! char replaces[Natts_pg_namespace]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; ! ! { pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); /* *************** *** 997,1003 **** ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE, ! nspname); } /* --- 1232,1238 ---- ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE, ! NameStr(pg_namespace_tuple->nspname)); } /* *************** *** 1042,1048 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 1277,1283 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 1068,1090 **** noldmembers, oldmembers, nnewmembers, newmembers); - ReleaseSysCache(tuple); - pfree(new_acl); - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Tablespace(GrantStmt *stmt) { AclMode privileges; bool all_privs; ListCell *i; if (stmt->privileges == NIL) { --- 1303,1325 ---- noldmembers, oldmembers, nnewmembers, newmembers); pfree(new_acl); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } } static void ! ExecuteGrantStmt_Tablespace(GrantStmt *stmt, Oid object, List *grantees) { AclMode privileges; bool all_privs; ListCell *i; + Relation relation; + + /* Only one of them should be given */ + Assert(OidIsValid(object) ^ (stmt->objects != NIL)); if (stmt->privileges == NIL) { *************** *** 1109,1152 **** } } ! foreach(i, stmt->objects) { ! char *spcname = strVal(lfirst(i)); ! Relation relation; ! ScanKeyData entry[1]; ! HeapScanDesc scan; ! HeapTuple tuple; ! Form_pg_tablespace pg_tablespace_tuple; ! Datum aclDatum; ! bool isNull; ! AclMode avail_goptions; ! AclMode this_privileges; ! Acl *old_acl; ! Acl *new_acl; ! Oid grantorId; ! Oid ownerId; ! HeapTuple newtuple; ! Datum values[Natts_pg_tablespace]; ! char nulls[Natts_pg_tablespace]; ! char replaces[Natts_pg_tablespace]; ! int noldmembers; ! int nnewmembers; ! Oid *oldmembers; ! Oid *newmembers; - relation = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], ! Anum_pg_tablespace_spcname, ! BTEqualStrategyNumber, F_NAMEEQ, ! CStringGetDatum(spcname)); scan = heap_beginscan(relation, SnapshotNow, 1, entry); tuple = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_OBJECT), ! errmsg("tablespace \"%s\" does not exist", spcname))); ! pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple); /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. --- 1344,1424 ---- } } ! relation = heap_open(TableSpaceRelationId, RowExclusiveLock); ! ! if (stmt->objects) { ! foreach (i, stmt->objects) ! { ! char *spcname = strVal(lfirst(i)); ! ScanKeyData entry[1]; ! HeapScanDesc scan; ! HeapTuple tuple; ! ! ScanKeyInit(&entry[0], ! Anum_pg_tablespace_spcname, ! BTEqualStrategyNumber, F_NAMEEQ, ! CStringGetDatum(spcname)); ! ! scan = heap_beginscan(relation, SnapshotNow, 1, entry); ! tuple = heap_getnext(scan, ForwardScanDirection); ! if (!HeapTupleIsValid(tuple)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_OBJECT), ! errmsg("tablespace \"%s\" does not exist", spcname))); ! ! ExecGrant_Tablespace(stmt, relation, tuple, privileges, all_privs, ! grantees); ! ! heap_endscan(scan); ! } ! } ! else ! { ! ScanKeyData entry[1]; ! HeapScanDesc scan; ! HeapTuple tuple; ScanKeyInit(&entry[0], ! ObjectIdAttributeNumber, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(object)); ! scan = heap_beginscan(relation, SnapshotNow, 1, entry); tuple = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for tablespace %u", object); + ExecGrant_Tablespace(stmt, relation, tuple, privileges, all_privs, + grantees); + + heap_endscan(scan); + } + } + + static void + ExecGrant_Tablespace(GrantStmt *stmt, Relation relation, HeapTuple tuple, + AclMode privileges, bool all_privs, List *grantees) + { + Form_pg_tablespace pg_tablespace_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_tablespace]; + char nulls[Natts_pg_tablespace]; + char replaces[Natts_pg_tablespace]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + { + pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple); /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. *************** *** 1176,1182 **** ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, ! spcname); } /* --- 1448,1454 ---- ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE), ACLMASK_ANY) == ACL_NO_RIGHTS) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, ! NameStr(pg_tablespace_tuple->spcname)); } /* *************** *** 1221,1227 **** new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! stmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 1493,1499 ---- new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); *************** *** 1249,1257 **** pfree(new_acl); - heap_endscan(scan); - heap_close(relation, RowExclusiveLock); - /* prevent error when processing duplicate objects */ CommandCounterIncrement(); } --- 1521,1526 ---- Index: src/backend/catalog/pg_depend.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_depend.c,v retrieving revision 1.15 diff -c -r1.15 pg_depend.c *** src/backend/catalog/pg_depend.c 15 Oct 2005 02:49:14 -0000 1.15 --- src/backend/catalog/pg_depend.c 18 Nov 2005 18:53:12 -0000 *************** *** 163,168 **** --- 163,219 ---- } /* + * objectIsInternalDependency -- return whether the specified object + * is listed as an internal dependency for some other object. + * + * This is used to implement DROP OWNED. We cannot invoke performDeletion + * blindly, because it may try to drop an internal dependency before the + * "main" object, so we need to skip the first object and expect it to be + * automatically dropped when the main object is dropped. + */ + bool + objectIsInternalDependency(Oid classId, Oid objectId) + { + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + bool isdep = false; + + depRel = heap_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + SnapshotNow, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup); + + if (depForm->deptype == DEPENDENCY_INTERNAL) + { + /* No need to keep scanning */ + isdep = true; + break; + } + } + + systable_endscan(scan); + + heap_close(depRel, AccessShareLock); + + return isdep; + } + + /* * Adjust dependency record(s) to point to a different object of the same type * * classId/objectId specify the referencing object. Index: src/backend/catalog/pg_shdepend.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v retrieving revision 1.3 diff -c -r1.3 pg_shdepend.c *** src/backend/catalog/pg_shdepend.c 15 Oct 2005 02:49:14 -0000 1.3 --- src/backend/catalog/pg_shdepend.c 18 Nov 2005 19:28:39 -0000 *************** *** 16,26 **** --- 16,39 ---- #include "access/genam.h" #include "access/heapam.h" + #include "utils/acl.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_authid.h" + #include "catalog/pg_conversion.h" #include "catalog/pg_database.h" + #include "catalog/pg_language.h" + #include "catalog/pg_namespace.h" + #include "catalog/pg_operator.h" + #include "catalog/pg_proc.h" #include "catalog/pg_shdepend.h" + #include "catalog/pg_tablespace.h" + #include "catalog/pg_type.h" + #include "commands/conversioncmds.h" + #include "commands/defrem.h" + #include "commands/schemacmds.h" + #include "commands/tablecmds.h" + #include "commands/typecmds.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "utils/fmgroids.h" *************** *** 1042,1044 **** --- 1055,1311 ---- return result; } + + /* + * shdepDropOwned + * + * Drop the objects owned by any one of the given RoleIds. If a role has + * access to an object, the grant will be removed as well (but the object + * will not, of course.) + */ + void + shdepDropOwned(List *roleids, DropBehavior behavior) + { + Relation sdepRel; + ListCell *cell; + + sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock); + + /* + * For each role, find the dependent objects and drop them using the + * regular (non-shared) dependency management. + */ + foreach(cell, roleids) + { + Oid roleid = lfirst_oid(cell); + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tuple; + + /* Doesn't work for pinned objects */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + { + ObjectAddress obj; + + obj.classId = AuthIdRelationId; + obj.objectId = roleid; + obj.objectSubId = 0; + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop objects owned by %s because they are " + "required by the database system", + getObjectDescription(&obj)))); + } + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(AuthIdRelationId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + SnapshotNow, 2, key); + + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); + + /* We only operate on objects on the current database */ + if (sdepForm->dbid != MyDatabaseId) + continue; + + switch (sdepForm->deptype) + { + ObjectAddress obj; + GrantStmt *stmt; + + /* Shouldn't happen */ + case SHARED_DEPENDENCY_PIN: + case SHARED_DEPENDENCY_INVALID: + elog(ERROR, "unexpected dependency type"); + break; + case SHARED_DEPENDENCY_ACL: + /* + * Revoke the permissions. It will get rid of the + * dependency automatically. + */ + stmt = makeNode(GrantStmt); + + stmt->is_grant = false; + stmt->objects = NIL; + stmt->grantees = NIL; + stmt->privileges = NIL; + + /* + * Both the permission itself and the grant option. Note + * the strange meaning of this flag in the REVOKE case. + */ + stmt->grant_option = false; + + stmt->behavior = behavior; + + switch (sdepForm->classid) + { + case RelationRelationId: + stmt->objtype = ACL_OBJECT_RELATION; + break; + case DatabaseRelationId: + stmt->objtype = ACL_OBJECT_DATABASE; + break; + case ProcedureRelationId: + stmt->objtype = ACL_OBJECT_FUNCTION; + break; + case LanguageRelationId: + stmt->objtype = ACL_OBJECT_LANGUAGE; + break; + case NamespaceRelationId: + stmt->objtype = ACL_OBJECT_NAMESPACE; + break; + case TableSpaceRelationId: + stmt->objtype = ACL_OBJECT_TABLESPACE; + break; + default: + elog(ERROR, "unexpected object type %d", + sdepForm->classid); + break; + } + + ExecuteGrantStmt(stmt, sdepForm->objid, roleid); + break; + case SHARED_DEPENDENCY_OWNER: + /* + * If there's a regular (non-shared) dependency on this + * object marked with DEPENDENCY_INTERNAL, skip this + * object. We will drop the referencer object instead. + */ + if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid)) + continue; + + /* Drop the object */ + obj.classId = sdepForm->classid; + obj.objectId = sdepForm->objid; + obj.objectSubId = 0; + performDeletion(&obj, behavior); + break; + } + } + + systable_endscan(scan); + } + + heap_close(sdepRel, AccessExclusiveLock); + } + + /* + * shdepReassignOwned + * + * Change the owner of objects owned by any of the roles in roleids to + * newrole. Grants are not touched. + */ + void + shdepReassignOwned(List *roleids, Oid newrole) + { + Relation sdepRel; + ListCell *cell; + + sdepRel = heap_open(SharedDependRelationId, AccessShareLock); + + foreach(cell, roleids) + { + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple tuple; + Oid roleid = lfirst_oid(cell); + + /* Refuse to work on pinned roles */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + { + ObjectAddress obj; + + obj.classId = AuthIdRelationId; + obj.objectId = roleid; + obj.objectSubId = 0; + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop objects owned by %s because they are " + "required by the database system", + getObjectDescription(&obj)))); + /* + * There's no need to tell the whole truth, which is that we + * didn't track these dependencies at all ... + */ + } + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(AuthIdRelationId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + SnapshotNow, 2, key); + + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); + + /* We only operate on objects on the current database */ + if (sdepForm->dbid != MyDatabaseId) + continue; + + /* Unexpected because we checked for pins above */ + if (sdepForm->deptype == SHARED_DEPENDENCY_PIN) + elog(ERROR, "unexpected shared pin"); + + /* We leave non-owner dependencies alone */ + if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER) + continue; + + /* Issue the appropiate ALTER OWNER call */ + switch (sdepForm->classid) + { + case ConversionRelationId: + AlterConversionOwner_oid(sdepForm->objid, newrole); + break; + + case TypeRelationId: + AlterTypeOwnerInternal(sdepForm->objid, newrole); + break; + + case OperatorRelationId: + AlterOperatorOwner_oid(sdepForm->objid, newrole); + break; + + case NamespaceRelationId: + AlterSchemaOwner_oid(sdepForm->objid, newrole); + break; + + case RelationRelationId: + ATExecChangeOwner(sdepForm->objid, newrole, false); + break; + + case ProcedureRelationId: + AlterFunctionOwner_oid(sdepForm->objid, newrole); + break; + + default: + elog(ERROR, "unexpected classid %d", sdepForm->classid); + break; + } + /* Make sure the next iteration will see my changes */ + CommandCounterIncrement(); + } + + systable_endscan(scan); + } + + heap_close(sdepRel, AccessShareLock); + } Index: src/backend/commands/conversioncmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/conversioncmds.c,v retrieving revision 1.23 diff -c -r1.23 conversioncmds.c *** src/backend/commands/conversioncmds.c 15 Oct 2005 02:49:15 -0000 1.23 --- src/backend/commands/conversioncmds.c 18 Nov 2005 19:28:00 -0000 *************** *** 30,35 **** --- 30,37 ---- #include "utils/lsyscache.h" #include "utils/syscache.h" + static void AlterConversionOwner_int(Relation rel, Oid conversionOid, + Oid newOwnerId); /* * CREATE CONVERSION *************** *** 172,187 **** } /* ! * Change conversion owner */ void AlterConversionOwner(List *name, Oid newOwnerId) { Oid conversionOid; - HeapTuple tup; Relation rel; - Form_pg_conversion convForm; - AclResult aclresult; rel = heap_open(ConversionRelationId, RowExclusiveLock); --- 174,186 ---- } /* ! * Change conversion owner, by name */ void AlterConversionOwner(List *name, Oid newOwnerId) { Oid conversionOid; Relation rel; rel = heap_open(ConversionRelationId, RowExclusiveLock); *************** *** 192,203 **** errmsg("conversion \"%s\" does not exist", NameListToString(name)))); tup = SearchSysCacheCopy(CONOID, ObjectIdGetDatum(conversionOid), 0, 0, 0); ! if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for conversion %u", conversionOid); - convForm = (Form_pg_conversion) GETSTRUCT(tup); /* --- 191,234 ---- errmsg("conversion \"%s\" does not exist", NameListToString(name)))); + AlterConversionOwner_int(rel, conversionOid, newOwnerId); + + heap_close(rel, NoLock); + } + + /* + * Change conversion owner, by oid + */ + void + AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId) + { + Relation rel; + + rel = heap_open(ConversionRelationId, RowExclusiveLock); + + AlterConversionOwner_int(rel, conversionOid, newOwnerId); + + heap_close(rel, NoLock); + } + + /* + * AlterConversionOwner_int + * + * Internal routine for changing the owner. rel must be pg_conversion, already + * open and suitably locked; it will not be closed. tup must be the tuple to + * which the owner is going to be changed. + */ + static void + AlterConversionOwner_int(Relation rel, Oid conversionOid, Oid newOwnerId) + { + Form_pg_conversion convForm; + HeapTuple tup; + tup = SearchSysCacheCopy(CONOID, ObjectIdGetDatum(conversionOid), 0, 0, 0); ! if (!HeapTupleIsValid(tup)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for conversion %u", conversionOid); convForm = (Form_pg_conversion) GETSTRUCT(tup); /* *************** *** 206,218 **** */ if (convForm->conowner != newOwnerId) { /* Superusers can always do it */ if (!superuser()) { /* Otherwise, must be owner of the existing object */ if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, ! NameListToString(name)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); --- 237,251 ---- */ if (convForm->conowner != newOwnerId) { + AclResult aclresult; + /* Superusers can always do it */ if (!superuser()) { /* Otherwise, must be owner of the existing object */ if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, ! NameStr(convForm->conname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); *************** *** 240,245 **** newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); } --- 273,277 ---- Index: src/backend/commands/functioncmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/functioncmds.c,v retrieving revision 1.69 diff -c -r1.69 functioncmds.c *** src/backend/commands/functioncmds.c 15 Oct 2005 02:49:15 -0000 1.69 --- src/backend/commands/functioncmds.c 26 Oct 2005 13:32:26 -0000 *************** *** 55,60 **** --- 55,61 ---- #include "utils/lsyscache.h" #include "utils/syscache.h" + static void AlterFunctionOwner_int(Relation rel, HeapTuple tup, Oid newOwnerId); /* * Examine the RETURNS clause of the CREATE FUNCTION statement *************** *** 853,868 **** } /* ! * Change function owner */ void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId) { Oid procOid; HeapTuple tup; - Form_pg_proc procForm; - Relation rel; - AclResult aclresult; rel = heap_open(ProcedureRelationId, RowExclusiveLock); --- 854,867 ---- } /* ! * Change function owner by name and args */ void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId) { + Relation rel; Oid procOid; HeapTuple tup; rel = heap_open(ProcedureRelationId, RowExclusiveLock); *************** *** 873,887 **** 0, 0, 0); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", procOid); - procForm = (Form_pg_proc) GETSTRUCT(tup); ! if (procForm->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", NameListToString(name)), errhint("Use ALTER AGGREGATE to change owner of aggregate functions."))); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. --- 872,924 ---- 0, 0, 0); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", procOid); ! if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an aggregate function", NameListToString(name)), errhint("Use ALTER AGGREGATE to change owner of aggregate functions."))); + AlterFunctionOwner_int(rel, tup, newOwnerId); + + heap_close(rel, NoLock); + } + + /* + * Change function owner by Oid + */ + void + AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId) + { + Relation rel; + HeapTuple tup; + + rel = heap_open(ProcedureRelationId, RowExclusiveLock); + + tup = SearchSysCache(PROCOID, + ObjectIdGetDatum(procOid), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for function %u", procOid); + AlterFunctionOwner_int(rel, tup, newOwnerId); + + heap_close(rel, NoLock); + } + + static void + AlterFunctionOwner_int(Relation rel, HeapTuple tup, Oid newOwnerId) + { + Form_pg_proc procForm; + AclResult aclresult; + Oid procOid; + + Assert(RelationGetRelid(rel) == ProcedureRelationId); + Assert(tup->t_tableOid == ProcedureRelationId); + + procForm = (Form_pg_proc) GETSTRUCT(tup); + procOid = HeapTupleGetOid(tup); + /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. *************** *** 902,908 **** /* Otherwise, must be owner of the existing object */ if (!pg_proc_ownercheck(procOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, ! NameListToString(name)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); --- 939,945 ---- /* Otherwise, must be owner of the existing object */ if (!pg_proc_ownercheck(procOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, ! NameStr(procForm->proname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); *************** *** 937,943 **** repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl); } ! newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); --- 974,981 ---- repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl); } ! newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, ! repl_null, repl_repl); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); *************** *** 949,955 **** } ReleaseSysCache(tup); - heap_close(rel, NoLock); } /* --- 987,992 ---- Index: src/backend/commands/opclasscmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/opclasscmds.c,v retrieving revision 1.38 diff -c -r1.38 opclasscmds.c *** src/backend/commands/opclasscmds.c 15 Oct 2005 02:49:15 -0000 1.38 --- src/backend/commands/opclasscmds.c 26 Oct 2005 13:32:27 -0000 *************** *** 58,63 **** --- 58,65 ---- static void addClassMember(List **list, OpClassMember *member, bool isProc); static void storeOperators(Oid opclassoid, List *operators); static void storeProcedures(Oid opclassoid, List *procedures); + static void AlterOpClassOwner_int(Relation rel, HeapTuple tuple, + Oid newOwnerId); /* *************** *** 879,898 **** } /* ! * Change opclass owner */ void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId) { - Oid opcOid; Oid amOid; - Oid namespaceOid; - char *schemaname; - char *opcname; - HeapTuple tup; Relation rel; ! AclResult aclresult; ! Form_pg_opclass opcForm; amOid = GetSysCacheOid(AMNAME, CStringGetDatum(access_method), --- 881,919 ---- } /* ! * Change opclass owner by oid ! */ ! void ! AlterOpClassOwner_oid(Oid opcOid, Oid newOwnerId) ! { ! Relation rel; ! HeapTuple tup; ! ! rel = heap_open(OperatorClassRelationId, RowExclusiveLock); ! ! tup = SearchSysCacheCopy(CLAOID, ! ObjectIdGetDatum(opcOid), ! 0, 0, 0); ! if (!HeapTupleIsValid(tup)) /* should not happen */ ! elog(ERROR, "cache lookup failed for opclass %u", opcOid); ! ! AlterOpClassOwner_int(rel, tup, newOwnerId); ! ! heap_freetuple(tup); ! heap_close(rel, NoLock); ! } ! ! /* ! * Change opclass owner by name */ void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId) { Oid amOid; Relation rel; ! HeapTuple tup; ! char *opcname; ! char *schemaname; amOid = GetSysCacheOid(AMNAME, CStringGetDatum(access_method), *************** *** 912,917 **** --- 933,940 ---- if (schemaname) { + Oid namespaceOid; + namespaceOid = LookupExplicitNamespace(schemaname); tup = SearchSysCacheCopy(CLAAMNAMENSP, *************** *** 924,934 **** (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("operator class \"%s\" does not exist for access method \"%s\"", opcname, access_method))); - - opcOid = HeapTupleGetOid(tup); } else { opcOid = OpclassnameGetOpcid(amOid, opcname); if (!OidIsValid(opcOid)) ereport(ERROR, --- 947,957 ---- (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("operator class \"%s\" does not exist for access method \"%s\"", opcname, access_method))); } else { + Oid opcOid; + opcOid = OpclassnameGetOpcid(amOid, opcname); if (!OidIsValid(opcOid)) ereport(ERROR, *************** *** 941,950 **** 0, 0, 0); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for opclass %u", opcOid); - namespaceOid = ((Form_pg_opclass) GETSTRUCT(tup))->opcnamespace; } opcForm = (Form_pg_opclass) GETSTRUCT(tup); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. --- 964,995 ---- 0, 0, 0); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for opclass %u", opcOid); } + + AlterOpClassOwner_int(rel, tup, newOwnerId); + + heap_freetuple(tup); + heap_close(rel, NoLock); + } + + /* + * The first parameter is pg_opclass, opened and suitably locked. The second + * parameter is the tuple from pg_opclass we want to modify. + */ + static void + AlterOpClassOwner_int(Relation rel, HeapTuple tup, Oid newOwnerId) + { + Oid namespaceOid; + AclResult aclresult; + Form_pg_opclass opcForm; + + Assert(tup->t_tableOid == OperatorClassRelationId); + Assert(RelationGetRelid(rel) == OperatorClassRelationId); + opcForm = (Form_pg_opclass) GETSTRUCT(tup); + namespaceOid = opcForm->opcnamespace; + /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. *************** *** 957,963 **** /* Otherwise, must be owner of the existing object */ if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, ! NameListToString(name)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); --- 1002,1008 ---- /* Otherwise, must be owner of the existing object */ if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, ! NameStr(opcForm->opcname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); *************** *** 980,988 **** CatalogUpdateIndexes(rel, tup); /* Update owner dependency reference */ ! changeDependencyOnOwner(OperatorClassRelationId, opcOid, newOwnerId); } - - heap_close(rel, NoLock); - heap_freetuple(tup); } --- 1025,1031 ---- CatalogUpdateIndexes(rel, tup); /* Update owner dependency reference */ ! changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup), ! newOwnerId); } } Index: src/backend/commands/operatorcmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/operatorcmds.c,v retrieving revision 1.26 diff -c -r1.26 operatorcmds.c *** src/backend/commands/operatorcmds.c 15 Oct 2005 02:49:15 -0000 1.26 --- src/backend/commands/operatorcmds.c 26 Oct 2005 13:32:29 -0000 *************** *** 48,53 **** --- 48,55 ---- #include "utils/syscache.h" + static void AlterOperatorOwner_int(Relation rel, Oid operOid, Oid newOwnerId); + /* * DefineOperator * this function extracts all the information from the *************** *** 260,265 **** --- 262,279 ---- heap_close(relation, RowExclusiveLock); } + void + AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId) + { + Relation rel; + + rel = heap_open(OperatorRelationId, RowExclusiveLock); + + AlterOperatorOwner_int(rel, operOid, newOwnerId); + + heap_close(rel, NoLock); + } + /* * change operator owner */ *************** *** 268,283 **** Oid newOwnerId) { Oid operOid; - HeapTuple tup; Relation rel; - AclResult aclresult; - Form_pg_operator oprForm; rel = heap_open(OperatorRelationId, RowExclusiveLock); operOid = LookupOperNameTypeNames(name, typeName1, typeName2, false); tup = SearchSysCacheCopy(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); --- 282,306 ---- Oid newOwnerId) { Oid operOid; Relation rel; rel = heap_open(OperatorRelationId, RowExclusiveLock); operOid = LookupOperNameTypeNames(name, typeName1, typeName2, false); + AlterOperatorOwner_int(rel, operOid, newOwnerId); + + heap_close(rel, NoLock); + } + + static void + AlterOperatorOwner_int(Relation rel, Oid operOid, Oid newOwnerId) + { + HeapTuple tup; + AclResult aclresult; + Form_pg_operator oprForm; + tup = SearchSysCacheCopy(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); *************** *** 298,304 **** /* Otherwise, must be owner of the existing object */ if (!pg_oper_ownercheck(operOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, ! NameListToString(name)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); --- 321,327 ---- /* Otherwise, must be owner of the existing object */ if (!pg_oper_ownercheck(operOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, ! NameStr(oprForm->oprname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); *************** *** 325,331 **** changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); - } --- 348,352 ---- Index: src/backend/commands/schemacmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/schemacmds.c,v retrieving revision 1.35 diff -c -r1.35 schemacmds.c *** src/backend/commands/schemacmds.c 15 Oct 2005 02:49:15 -0000 1.35 --- src/backend/commands/schemacmds.c 26 Oct 2005 13:32:29 -0000 *************** *** 31,36 **** --- 31,38 ---- #include "utils/syscache.h" + static void AlterSchemaOwner_int(HeapTuple tup, Relation rel, Oid newOwnerId); + /* * CREATE SCHEMA */ *************** *** 264,269 **** --- 266,293 ---- heap_freetuple(tup); } + void + AlterSchemaOwner_oid(Oid oid, Oid newOwnerId) + { + HeapTuple tup; + Relation rel; + + rel = heap_open(NamespaceRelationId, RowExclusiveLock); + + tup = SearchSysCache(NAMESPACEOID, + ObjectIdGetDatum(oid), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for schema %u", oid); + + AlterSchemaOwner_int(tup, rel, newOwnerId); + + ReleaseSysCache(tup); + + heap_close(rel, RowExclusiveLock); + } + + /* * Change schema owner */ *************** *** 272,278 **** { HeapTuple tup; Relation rel; - Form_pg_namespace nspForm; rel = heap_open(NamespaceRelationId, RowExclusiveLock); --- 296,301 ---- *************** *** 283,288 **** --- 306,324 ---- ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", name))); + + AlterSchemaOwner_int(tup, rel, newOwnerId); + + ReleaseSysCache(tup); + + heap_close(rel, RowExclusiveLock); + } + + static void + AlterSchemaOwner_int(HeapTuple tup, Relation rel, Oid newOwnerId) + { + Form_pg_namespace nspForm; + nspForm = (Form_pg_namespace) GETSTRUCT(tup); /* *************** *** 303,309 **** /* Otherwise, must be owner of the existing object */ if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, ! name); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); --- 339,345 ---- /* Otherwise, must be owner of the existing object */ if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, ! NameStr(nspForm->nspname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); *************** *** 356,361 **** newOwnerId); } - ReleaseSysCache(tup); - heap_close(rel, NoLock); } --- 392,395 ---- Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.174 diff -c -r1.174 tablecmds.c *** src/backend/commands/tablecmds.c 15 Oct 2005 02:49:15 -0000 1.174 --- src/backend/commands/tablecmds.c 26 Oct 2005 13:32:30 -0000 *************** *** 236,242 **** const char *colName, TypeName *typename); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab); static void ATPostAlterTypeParse(char *cmd, List **wqueue); - static void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing); static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId); static void ATExecClusterOn(Relation rel, const char *indexName); --- 236,241 ---- *************** *** 5264,5270 **** * checks (this is necessary not just an optimization, else we'd fail to * handle toast tables properly). */ ! static void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) { Relation target_rel; --- 5263,5269 ---- * checks (this is necessary not just an optimization, else we'd fail to * handle toast tables properly). */ ! void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) { Relation target_rel; Index: src/backend/commands/typecmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/typecmds.c,v retrieving revision 1.82 diff -c -r1.82 typecmds.c *** src/backend/commands/typecmds.c 18 Oct 2005 01:06:24 -0000 1.82 --- src/backend/commands/typecmds.c 26 Oct 2005 13:32:31 -0000 *************** *** 2096,2102 **** * AlterTypeOwnerInternal - change type owner unconditionally * * This is currently only used to propagate ALTER TABLE OWNER to the ! * table's rowtype. It assumes the caller has done all needed checks. */ void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) --- 2096,2103 ---- * AlterTypeOwnerInternal - change type owner unconditionally * * This is currently only used to propagate ALTER TABLE OWNER to the ! * table's rowtype, and to implement REASSIGN OWNED BY. It assumes the ! * caller has done all needed checks. */ void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) Index: src/backend/commands/user.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/user.c,v retrieving revision 1.164 diff -c -r1.164 user.c *** src/backend/commands/user.c 4 Nov 2005 17:25:15 -0000 1.164 --- src/backend/commands/user.c 18 Nov 2005 19:31:18 -0000 *************** *** 1119,1124 **** --- 1119,1185 ---- } /* + * DropOwnedObjects + * + * Drop the objects owned by a given list of roles. + */ + void + DropOwnedObjects(DropOwnedStmt *stmt) + { + List *role_ids = roleNamesToIds(stmt->roles); + ListCell *cell; + + /* Check privileges */ + foreach (cell, role_ids) + { + Oid roleid = lfirst_oid(cell); + + if (!has_privs_of_role(GetUserId(), roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to drop objects"))); + } + + /* Ok, do it */ + shdepDropOwned(role_ids, stmt->behavior); + } + + /* + * ReassignOwnedObjects + * + * Give the objects owned by a given list of roles away to another user. + */ + void + ReassignOwnedObjects(ReassignOwnedStmt *stmt) + { + List *role_ids = roleNamesToIds(stmt->roles); + ListCell *cell; + Oid newrole; + + /* Check privileges */ + foreach (cell, role_ids) + { + Oid roleid = lfirst_oid(cell); + + if (!has_privs_of_role(GetUserId(), roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to reassign objects"))); + } + + /* Must have privileges on the receiving side too */ + newrole = get_roleid_checked(stmt->newrole); + + if (!has_privs_of_role(GetUserId(), newrole)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to reassign objects"))); + + /* Ok, do it */ + shdepReassignOwned(role_ids, newrole); + } + + /* * roleNamesToIds * * Given a list of role names (as String nodes), generate a list of role OIDs Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.317 diff -c -r1.317 copyfuncs.c *** src/backend/nodes/copyfuncs.c 14 Nov 2005 23:54:12 -0000 1.317 --- src/backend/nodes/copyfuncs.c 18 Nov 2005 19:00:26 -0000 *************** *** 2594,2599 **** --- 2594,2620 ---- return newnode; } + static DropOwnedStmt * + _copyDropOwnedStmt(DropOwnedStmt *from) + { + DropOwnedStmt *newnode = makeNode(DropOwnedStmt); + + COPY_NODE_FIELD(roles); + COPY_SCALAR_FIELD(behavior); + + return newnode; + } + + static ReassignOwnedStmt * + _copyReassignOwnedStmt(ReassignOwnedStmt *from) + { + ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt); + + COPY_NODE_FIELD(roles); + COPY_SCALAR_FIELD(newrole); + + return newnode; + } /* **************************************************************** * pg_list.h copy functions *************** *** 3145,3150 **** --- 3166,3177 ---- case T_DeallocateStmt: retval = _copyDeallocateStmt(from); break; + case T_DropOwnedStmt: + retval = _copyDropOwnedStmt(from); + break; + case T_ReassignOwnedStmt: + retval = _copyReassignOwnedStmt(from); + break; case T_A_Expr: retval = _copyAExpr(from); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.254 diff -c -r1.254 equalfuncs.c *** src/backend/nodes/equalfuncs.c 14 Nov 2005 23:54:15 -0000 1.254 --- src/backend/nodes/equalfuncs.c 18 Nov 2005 19:00:37 -0000 *************** *** 1468,1477 **** return true; } ! /* ! * stuff from parsenodes.h ! */ static bool _equalAExpr(A_Expr *a, A_Expr *b) --- 1468,1490 ---- return true; } + static bool + _equalDropOwnedStmt(DropOwnedStmt *a, DropOwnedStmt *b) + { + COMPARE_NODE_FIELD(roles); + COMPARE_SCALAR_FIELD(behavior); ! return true; ! } ! ! static bool ! _equalReassignOwnedStmt(ReassignOwnedStmt *a, ReassignOwnedStmt *b) ! { ! COMPARE_NODE_FIELD(roles); ! COMPARE_NODE_FIELD(newrole); ! ! return true; ! } static bool _equalAExpr(A_Expr *a, A_Expr *b) *************** *** 2187,2192 **** --- 2200,2212 ---- case T_DeallocateStmt: retval = _equalDeallocateStmt(a, b); break; + case T_DropOwnedStmt: + retval = _equalDropOwnedStmt(a, b); + break; + + case T_ReassignOwnedStmt: + retval = _equalReassignOwnedStmt(a, b); + break; case T_A_Expr: retval = _equalAExpr(a, b); Index: src/backend/parser/gram.y =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/parser/gram.y,v retrieving revision 2.512 diff -c -r2.512 gram.y *** src/backend/parser/gram.y 13 Nov 2005 19:11:28 -0000 2.512 --- src/backend/parser/gram.y 18 Nov 2005 19:33:08 -0000 *************** *** 153,158 **** --- 153,159 ---- VariableResetStmt VariableSetStmt VariableShowStmt ViewStmt CheckPointStmt CreateConversionStmt DeallocateStmt PrepareStmt ExecuteStmt + DropOwnedStmt ReassignOwnedStmt %type select_no_parens select_with_parens select_clause simple_select *************** *** 382,388 **** NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ! ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER PARTIAL PASSWORD PLACING POSITION PRECISION PRESERVE PREPARE PREPARED PRIMARY --- 383,389 ---- NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ! ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER PARTIAL PASSWORD PLACING POSITION PRECISION PRESERVE PREPARE PREPARED PRIMARY *************** *** 390,396 **** QUOTE ! READ REAL RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE --- 391,397 ---- QUOTE ! READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE *************** *** 533,538 **** --- 534,540 ---- | DropCastStmt | DropGroupStmt | DropOpClassStmt + | DropOwnedStmt | DropPLangStmt | DropRuleStmt | DropStmt *************** *** 553,558 **** --- 555,561 ---- | LockStmt | NotifyStmt | PrepareStmt + | ReassignOwnedStmt | ReindexStmt | RemoveAggrStmt | RemoveFuncStmt *************** *** 2813,2818 **** --- 2816,2848 ---- } ; + /***************************************************************************** + * + * QUERY: + * + * DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ] + * REASSIGN OWNED BY username [, username ...] TO username + * + *****************************************************************************/ + DropOwnedStmt: + DROP OWNED BY name_list opt_drop_behavior + { + DropOwnedStmt *n = makeNode(DropOwnedStmt); + n->roles = $4; + n->behavior = $5; + $$ = (Node *)n; + } + ; + + ReassignOwnedStmt: + REASSIGN OWNED BY name_list TO name + { + ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt); + n->roles = $4; + n->newrole = $6; + $$ = (Node *)n; + } + ; /***************************************************************************** * *************** *** 8209,8214 **** --- 8239,8245 ---- | OIDS | OPERATOR | OPTION + | OWNED | OWNER | PARTIAL | PASSWORD *************** *** 8221,8226 **** --- 8252,8258 ---- | PROCEDURE | QUOTE | READ + | REASSIGN | RECHECK | REINDEX | RELATIVE_P Index: src/backend/parser/keywords.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/parser/keywords.c,v retrieving revision 1.166 diff -c -r1.166 keywords.c *** src/backend/parser/keywords.c 15 Oct 2005 02:49:22 -0000 1.166 --- src/backend/parser/keywords.c 26 Oct 2005 13:32:40 -0000 *************** *** 251,256 **** --- 251,257 ---- {"outer", OUTER_P}, {"overlaps", OVERLAPS}, {"overlay", OVERLAY}, + {"owned", OWNED}, {"owner", OWNER}, {"partial", PARTIAL}, {"password", PASSWORD}, *************** *** 268,273 **** --- 269,275 ---- {"quote", QUOTE}, {"read", READ}, {"real", REAL}, + {"reassign", REASSIGN}, {"recheck", RECHECK}, {"references", REFERENCES}, {"reindex", REINDEX}, Index: src/backend/tcop/utility.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/tcop/utility.c,v retrieving revision 1.245 diff -c -r1.245 utility.c *** src/backend/tcop/utility.c 15 Oct 2005 02:49:27 -0000 1.245 --- src/backend/tcop/utility.c 26 Oct 2005 13:32:55 -0000 *************** *** 319,324 **** --- 319,326 ---- case T_GrantStmt: case T_GrantRoleStmt: case T_TruncateStmt: + case T_DropOwnedStmt: + case T_ReassignOwnedStmt: ereport(ERROR, (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), errmsg("transaction is read-only"))); *************** *** 681,687 **** break; case T_GrantStmt: ! ExecuteGrantStmt((GrantStmt *) parsetree); break; case T_GrantRoleStmt: --- 683,689 ---- break; case T_GrantStmt: ! ExecuteGrantStmt((GrantStmt *) parsetree, InvalidOid, InvalidOid); break; case T_GrantRoleStmt: *************** *** 983,988 **** --- 985,998 ---- DropRole((DropRoleStmt *) parsetree); break; + case T_DropOwnedStmt: + DropOwnedObjects((DropOwnedStmt *) parsetree); + break; + + case T_ReassignOwnedStmt: + ReassignOwnedObjects((ReassignOwnedStmt *) parsetree); + break; + case T_LockStmt: LockTableCommand((LockStmt *) parsetree); break; *************** *** 1641,1646 **** --- 1651,1664 ---- tag = "DROP ROLE"; break; + case T_DropOwnedStmt: + tag = "DROP OWNED"; + break; + + case T_ReassignOwnedStmt: + tag = "REASSIGN OWNED"; + break; + case T_LockStmt: tag = "LOCK TABLE"; break; Index: src/include/catalog/dependency.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/dependency.h,v retrieving revision 1.17 diff -c -r1.17 dependency.h *** src/include/catalog/dependency.h 15 Oct 2005 02:49:42 -0000 1.17 --- src/include/catalog/dependency.h 18 Nov 2005 18:51:41 -0000 *************** *** 177,182 **** --- 177,184 ---- Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); + extern bool objectIsInternalDependency(Oid classId, Oid objectId); + /* in pg_shdepend.c */ extern void recordSharedDependencyOn(ObjectAddress *depender, *************** *** 201,204 **** --- 203,210 ---- extern void dropDatabaseDependencies(Oid databaseId); + extern void shdepDropOwned(List *relids, DropBehavior behavior); + + extern void shdepReassignOwned(List *relids, Oid newrole); + #endif /* DEPENDENCY_H */ Index: src/include/commands/conversioncmds.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/conversioncmds.h,v retrieving revision 1.10 diff -c -r1.10 conversioncmds.h *** src/include/commands/conversioncmds.h 28 Jun 2005 05:09:12 -0000 1.10 --- src/include/commands/conversioncmds.h 18 Nov 2005 14:52:05 -0000 *************** *** 21,25 **** --- 21,26 ---- extern void DropConversionCommand(List *conversion_name, DropBehavior behavior); extern void RenameConversion(List *name, const char *newname); extern void AlterConversionOwner(List *name, Oid newOwnerId); + extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId); #endif /* CONVERSIONCMDS_H */ Index: src/include/commands/defrem.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/defrem.h,v retrieving revision 1.68 diff -c -r1.68 defrem.h *** src/include/commands/defrem.h 15 Oct 2005 02:49:44 -0000 1.68 --- src/include/commands/defrem.h 26 Oct 2005 13:33:16 -0000 *************** *** 51,56 **** --- 51,57 ---- extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType); extern void RenameFunction(List *name, List *argtypes, const char *newname); extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId); + extern void AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId); extern void AlterFunction(AlterFunctionStmt *stmt); extern void CreateCast(CreateCastStmt *stmt); extern void DropCast(DropCastStmt *stmt); *************** *** 64,69 **** --- 65,71 ---- extern void RemoveOperatorById(Oid operOid); extern void AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typename2, Oid newOwnerId); + extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId); /* commands/aggregatecmds.c */ extern void DefineAggregate(List *names, List *parameters); *************** *** 77,82 **** --- 79,85 ---- extern void RemoveOpClassById(Oid opclassOid); extern void RenameOpClass(List *name, const char *access_method, const char *newname); extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId); + extern void AlterOpClassOwner_oid(Oid opcOid, Oid newOwnerId); /* support routines in commands/define.c */ Index: src/include/commands/schemacmds.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/schemacmds.h,v retrieving revision 1.10 diff -c -r1.10 schemacmds.h *** src/include/commands/schemacmds.h 28 Jun 2005 05:09:12 -0000 1.10 --- src/include/commands/schemacmds.h 19 Aug 2005 16:02:34 -0000 *************** *** 24,28 **** --- 24,29 ---- extern void RenameSchema(const char *oldname, const char *newname); extern void AlterSchemaOwner(const char *name, Oid newOwnerId); + extern void AlterSchemaOwner_oid(const Oid schemaOid, Oid newOwnerId); #endif /* SCHEMACMDS_H */ Index: src/include/commands/tablecmds.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/tablecmds.h,v retrieving revision 1.24 diff -c -r1.24 tablecmds.h *** src/include/commands/tablecmds.h 15 Oct 2005 02:49:44 -0000 1.24 --- src/include/commands/tablecmds.h 26 Oct 2005 13:33:17 -0000 *************** *** 24,29 **** --- 24,31 ---- extern void AlterTable(AlterTableStmt *stmt); + extern void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing); + extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); extern void AlterTableCreateToastTable(Oid relOid, bool silent); Index: src/include/commands/user.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/user.h,v retrieving revision 1.27 diff -c -r1.27 user.h *** src/include/commands/user.h 28 Jun 2005 05:09:12 -0000 1.27 --- src/include/commands/user.h 13 Sep 2005 22:23:15 -0000 *************** *** 20,24 **** --- 20,26 ---- extern void DropRole(DropRoleStmt *stmt); extern void GrantRole(GrantRoleStmt *stmt); extern void RenameRole(const char *oldname, const char *newname); + extern void DropOwnedObjects(DropOwnedStmt *stmt); + extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt); #endif /* USER_H */ Index: src/include/nodes/nodes.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/nodes/nodes.h,v retrieving revision 1.176 diff -c -r1.176 nodes.h *** src/include/nodes/nodes.h 15 Oct 2005 02:49:45 -0000 1.176 --- src/include/nodes/nodes.h 26 Oct 2005 13:33:18 -0000 *************** *** 286,291 **** --- 286,293 ---- T_DropTableSpaceStmt, T_AlterObjectSchemaStmt, T_AlterOwnerStmt, + T_DropOwnedStmt, + T_ReassignOwnedStmt, T_A_Expr = 800, T_ColumnRef, Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/nodes/parsenodes.h,v retrieving revision 1.292 diff -c -r1.292 parsenodes.h *** src/include/nodes/parsenodes.h 26 Oct 2005 19:21:55 -0000 1.292 --- src/include/nodes/parsenodes.h 18 Nov 2005 19:02:18 -0000 *************** *** 1874,1877 **** --- 1874,1897 ---- char *name; /* The name of the plan to remove */ } DeallocateStmt; + /* + * DROP OWNED statement + */ + typedef struct DropOwnedStmt + { + NodeTag type; + List *roles; + DropBehavior behavior; + } DropOwnedStmt; + + /* + * REASSIGN OWNED statement + */ + typedef struct ReassignOwnedStmt + { + NodeTag type; + List *roles; + char *newrole; + } ReassignOwnedStmt; + #endif /* PARSENODES_H */ Index: src/include/utils/acl.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v retrieving revision 1.88 diff -c -r1.88 acl.h *** src/include/utils/acl.h 18 Nov 2005 02:38:24 -0000 1.88 --- src/include/utils/acl.h 18 Nov 2005 14:09:11 -0000 *************** *** 220,226 **** /* * prototypes for functions in aclchk.c */ ! extern void ExecuteGrantStmt(GrantStmt *stmt); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how); --- 220,226 ---- /* * prototypes for functions in aclchk.c */ ! extern void ExecuteGrantStmt(GrantStmt *stmt, Oid object, Oid grantee); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how);