public inbox for [email protected]
help / color / mirror / Atom feedDROP OWNED again
10+ messages / 4 participants
[nested] [flat]
* DROP OWNED again
@ 2005-11-18 19:54 Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
0 siblings, 1 reply; 10+ messages in thread
From: Alvaro Herrera @ 2005-11-18 19:54 UTC (permalink / raw)
To: Patches <[email protected]>
People,
Here is the patch for DROP OWNED (finally!). This patch implements two
new commands, DROP OWNED and REASSIGN OWNED BY.
DROP OWNED drops the objects owned by any of a list of roles (in the
current database, of course). It also revokes all privileges that have
been granted to any of them. One must have privileges of all the
mentioned roles in order to be able to do this. (So a superuser can do
it for any role, and in the simple case a role can do it only to
itself.)
REASSIGN OWNED gives the objects away to some other role. It doesn't
touch grants. So if a role has been granted something and you want to
drop it but keep the objects, you must do REASSIGN OWNED and then DROP
OWNED. One must have all privileges of all the mentioned roles in
order to do this, including the receiving role.
The idea of all this is that if you want to drop a role, you first issue
a DROP ROLE, note all the databases on which it says it has dependences,
connect to each and issue REASSIGN OWNED and/or DROP OWNED as
appropiate, and finally issue DROP ROLE again. This eases dropping a
role (or that is the theory anyway).
The patch is missing regression tests. I will include them when I apply
it. I intend to apply it tomorrow or so, unless somebody has (strong?
Is the time when people "strongly objected" to things gone?) objections
to it.
--
Alvaro Herrera http://www.PlanetPostgreSQL.org
"La rebeldÃa es la virtud original del hombre" (Arthur Schopenhauer)
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 ----
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
+ <!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
***************
*** 93,98 ****
--- 94,100 ----
<!entity notify system "notify.sgml">
<!entity prepare system "prepare.sgml">
<!entity prepareTransaction system "prepare_transaction.sgml">
+ <!entity reassignOwned system "reassign_owned.sgml">
<!entity reindex system "reindex.sgml">
<!entity releaseSavepoint system "release_savepoint.sgml">
<!entity reset system "reset.sgml">
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 <node> 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);
<!--
$PostgreSQL$
PostgreSQL documentation
-->
<refentry id="SQL-DROP-OWNED">
<refmeta>
<refentrytitle id="SQL-DROP-OWNED-TITLE">DROP OWNED</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP OWNED</refname>
<refpurpose>remove database objects owned by a database role</refpurpose>
</refnamediv>
<indexterm zone="sql-drop-owned">
<primary>DROP OWNED</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP OWNED <replaceable class="PARAMETER">name</replaceable> [, ...] [ RESTRICT | CASCADE ]
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>DROP OWNED</command> instructs the system to drop those
database objects owned by one of the given roles which reside on the
current database. All privileges granted to the given roles will also be
revoked.
</para>
<para>
If <literal>CASCADE</> is specified, <command>DROP OWNED</command>
will behave like a <command>DROP ... CASCADE</command> was issued
for each object, that is, objects dependent on the ones owned by the
given users will be dropped as well.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The <command>DROP OWNED</command> command is mostly used in preparation to
drop the roles. It may be necessary to issue the command in more than one
database.
</para>
<para>
Using the <literal>CASCADE</literal> option may make the command recurse to
objects owned by other users.
</para>
<para>
See the <command>REASSIGN OWNED</command> command for an alternative that
gives the objects away to another role.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
The <command>DROP OWNED</command> statement is a
<productname>PostgreSQL</productname> extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-reassign-owned" endterm="sql-reassign-owned-title"></member>
<member><xref linkend="sql-droprole" endterm="sql-droprole-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!--
$PostgreSQL$
PostgreSQL documentation
-->
<refentry id="SQL-REASSIGN-OWNED">
<refmeta>
<refentrytitle id="SQL-REASSIGN-OWNED-TITLE">REASSIGN OWNED</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>REASSIGN OWNED</refname>
<refpurpose>change ownership of database objects owned by a database role</refpurpose>
</refnamediv>
<indexterm zone="sql-reassign-owned">
<primary>REASSIGN OWNED</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
REASSIGN OWNED <replaceable class="PARAMETER">old_role</replaceable> [, ...] TO <replaceable class="PARAMETER">new_role</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>REASSIGN OWNED</command> instructs the system to change
the ownership of the database objects owned by one of the old_roles,
to new_role.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The <command>REASSIGN OWNED</command> command is mostly used in preparation to
drop the roles. See the <command>DROP OWNED</command> command for an
alternative that drops the objects.
</para>
<para>
The <command>REASSIGN OWNED</command> command does not affect the privileges
granted to the old_roles in objects not owned by them. Use
<command>DROP OWNED</command> to remove them.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
The <command>REASSIGN OWNED</command> statement is a
<productname>PostgreSQL</productname> extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-drop-owned" endterm="sql-drop-owned-title"></member>
<member><xref linkend="sql-droprole" endterm="sql-droprole-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
Attachments:
[text/plain] drop-owned-3.patch (87.8K, 2-drop-owned-3.patch)
download | inline diff:
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 ----
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
+ <!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
***************
*** 93,98 ****
--- 94,100 ----
<!entity notify system "notify.sgml">
<!entity prepare system "prepare.sgml">
<!entity prepareTransaction system "prepare_transaction.sgml">
+ <!entity reassignOwned system "reassign_owned.sgml">
<!entity reindex system "reindex.sgml">
<!entity releaseSavepoint system "release_savepoint.sgml">
<!entity reset system "reset.sgml">
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 <node> 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);
[text/plain] drop_owned.sgml (2.5K, 3-drop_owned.sgml)
download | inline:
<!--
$PostgreSQL$
PostgreSQL documentation
-->
<refentry id="SQL-DROP-OWNED">
<refmeta>
<refentrytitle id="SQL-DROP-OWNED-TITLE">DROP OWNED</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP OWNED</refname>
<refpurpose>remove database objects owned by a database role</refpurpose>
</refnamediv>
<indexterm zone="sql-drop-owned">
<primary>DROP OWNED</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP OWNED <replaceable class="PARAMETER">name</replaceable> [, ...] [ RESTRICT | CASCADE ]
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>DROP OWNED</command> instructs the system to drop those
database objects owned by one of the given roles which reside on the
current database. All privileges granted to the given roles will also be
revoked.
</para>
<para>
If <literal>CASCADE</> is specified, <command>DROP OWNED</command>
will behave like a <command>DROP ... CASCADE</command> was issued
for each object, that is, objects dependent on the ones owned by the
given users will be dropped as well.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The <command>DROP OWNED</command> command is mostly used in preparation to
drop the roles. It may be necessary to issue the command in more than one
database.
</para>
<para>
Using the <literal>CASCADE</literal> option may make the command recurse to
objects owned by other users.
</para>
<para>
See the <command>REASSIGN OWNED</command> command for an alternative that
gives the objects away to another role.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
The <command>DROP OWNED</command> statement is a
<productname>PostgreSQL</productname> extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-reassign-owned" endterm="sql-reassign-owned-title"></member>
<member><xref linkend="sql-droprole" endterm="sql-droprole-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
[text/plain] reassign_owned.sgml (2.2K, 4-reassign_owned.sgml)
download | inline:
<!--
$PostgreSQL$
PostgreSQL documentation
-->
<refentry id="SQL-REASSIGN-OWNED">
<refmeta>
<refentrytitle id="SQL-REASSIGN-OWNED-TITLE">REASSIGN OWNED</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>REASSIGN OWNED</refname>
<refpurpose>change ownership of database objects owned by a database role</refpurpose>
</refnamediv>
<indexterm zone="sql-reassign-owned">
<primary>REASSIGN OWNED</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
REASSIGN OWNED <replaceable class="PARAMETER">old_role</replaceable> [, ...] TO <replaceable class="PARAMETER">new_role</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
The <command>REASSIGN OWNED</command> instructs the system to change
the ownership of the database objects owned by one of the old_roles,
to new_role.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The <command>REASSIGN OWNED</command> command is mostly used in preparation to
drop the roles. See the <command>DROP OWNED</command> command for an
alternative that drops the objects.
</para>
<para>
The <command>REASSIGN OWNED</command> command does not affect the privileges
granted to the old_roles in objects not owned by them. Use
<command>DROP OWNED</command> to remove them.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
The <command>REASSIGN OWNED</command> statement is a
<productname>PostgreSQL</productname> extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-drop-owned" endterm="sql-drop-owned-title"></member>
<member><xref linkend="sql-droprole" endterm="sql-droprole-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: DROP OWNED again
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
@ 2005-11-19 00:59 ` Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
0 siblings, 1 reply; 10+ messages in thread
From: Tom Lane @ 2005-11-19 00:59 UTC (permalink / raw)
To: Alvaro Herrera <[email protected]>; +Cc: Patches <[email protected]>
Alvaro Herrera <[email protected]> writes:
> /*
> ! * 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)
This seems like a really ugly API. What's so hard about expecting the
caller to construct a valid GrantStmt?
(I get the impression from a quick scan of the code that the comment
is a long way from telling the truth about what's really happening,
either.)
> + static void AlterConversionOwner_int(Relation rel, Oid conversionOid,
> + Oid newOwnerId);
If these are supposed to mean "AlterConversionOwner_internal", please
spell them that way. Sitting beside "AlterConversionOwner_oid", it
sure looks like the "int" is meant to be read as "integer".
regards, tom lane
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: DROP OWNED again
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
@ 2005-11-19 22:55 ` Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
0 siblings, 1 reply; 10+ messages in thread
From: Alvaro Herrera @ 2005-11-19 22:55 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Patches <[email protected]>
Tom Lane wrote:
> Alvaro Herrera <[email protected]> writes:
> > /*
> > ! * 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)
>
> This seems like a really ugly API. What's so hard about expecting the
> caller to construct a valid GrantStmt?
Well, a valid GrantStmt wants to have textual names of objects, so I
figured it would be best to offer both alternatives to the caller, while
at the same time not having to look up some things twice: there are
several syscaches for both names and Oids, so if you can get the
object's tuple using the name syscache, why not use it directly?
The attached does not attempt to save the second lookup, but it seems
better code -- it offers two entry points, one with GrantStmt just as
it's not, and another one with only Oids. The former calls the latter
upon looking up the object's Oids. So it's somewhat more inefficient,
though probably negligibly so.
> (I get the impression from a quick scan of the code that the comment
> is a long way from telling the truth about what's really happening,
> either.)
Hmm, not sure why you would think so, but it doesn't matter now.
> > + static void AlterConversionOwner_int(Relation rel, Oid conversionOid,
> > + Oid newOwnerId);
>
> If these are supposed to mean "AlterConversionOwner_internal", please
> spell them that way. Sitting beside "AlterConversionOwner_oid", it
> sure looks like the "int" is meant to be read as "integer".
Sure -- done.
I have added the regression tests in this new version, which I'll apply
on monday barring any objections. (I do not attach the SGML files
because these didn't change since the last post.)
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 70,75 ****
--- 70,76 ----
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
+ <!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
***************
*** 93,98 ****
--- 94,100 ----
<!entity notify system "notify.sgml">
<!entity prepare system "prepare.sgml">
<!entity prepareTransaction system "prepare_transaction.sgml">
+ <!entity reassignOwned system "reassign_owned.sgml">
<!entity reindex system "reindex.sgml">
<!entity releaseSavepoint system "release_savepoint.sgml">
<!entity reset system "reset.sgml">
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 19 Nov 2005 21:36:24 -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,66 ----
#include "utils/syscache.h"
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
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.
--- 110,119 ----
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.
***************
*** 151,221 ****
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",
(int) stmt->objtype);
}
- }
-
-
- static void
- ExecuteGrantStmt_Relation(GrantStmt *stmt)
- {
- AclMode privileges;
- bool all_privs;
- ListCell *i;
if (stmt->privileges == NIL)
{
all_privs = true;
! privileges = ACL_ALL_RIGHTS_RELATION;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
! foreach(i, stmt->privileges)
{
! char *privname = strVal(lfirst(i));
AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for table",
privilege_to_string(priv))));
privileges |= priv;
}
}
! 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;
--- 160,466 ----
void
ExecuteGrantStmt(GrantStmt *stmt)
{
+ List *objects;
+ List *grantees = NIL;
+ AclMode privileges;
+ ListCell *cell;
+ bool all_privs;
+ AclMode all_privileges = (AclMode) 0;
+ char *errormsg = NULL;
+
+ /*
+ * Convert the PrivGrantee list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if an empty role name is
+ * detected (which is what the grammar uses if PUBLIC is found), so
+ * downstream there shouldn't be any additional work needed to support this
+ * case.
+ */
+ 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));
+ }
+
+ /*
+ * Convert stmt->privileges, a textual list, into an AclMode bitmask
+ * appropiate for the given object class.
+ */
switch (stmt->objtype)
{
case ACL_OBJECT_RELATION:
! all_privileges = ACL_ALL_RIGHTS_RELATION;
! errormsg = _("invalid privilege type %s for table");
break;
case ACL_OBJECT_DATABASE:
! all_privileges = ACL_ALL_RIGHTS_DATABASE;
! errormsg = _("invalid privilege type %s for database");
break;
case ACL_OBJECT_FUNCTION:
! all_privileges = ACL_ALL_RIGHTS_FUNCTION;
! errormsg = _("invalid privilege type %s for function");
break;
case ACL_OBJECT_LANGUAGE:
! all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
! errormsg = _("invalid privilege type %s for language");
break;
case ACL_OBJECT_NAMESPACE:
! all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
! errormsg = _("invalid privilege type %s for namespace");
break;
case ACL_OBJECT_TABLESPACE:
! all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
! errormsg = _("invalid privilege type %s for tablespace");
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
all_privs = true;
! privileges = all_privileges;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
! foreach(cell, stmt->privileges)
{
! char *privname = strVal(lfirst(cell));
AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) all_privileges))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg(errormsg,
privilege_to_string(priv))));
+
privileges |= priv;
}
}
! /* Turn the list of object names into an Oid list */
! objects = objectNamesToOids(stmt->objtype, stmt->objects);
!
! ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! privileges, grantees, stmt->grant_option,
! stmt->behavior);
! }
!
! /*
! * ExecGrantStmt_oids
! *
! * "Internal" entrypoint for granting and revoking privileges. The arguments
! * it receives are lists of Oids or have been otherwise converted from text
! * format to internal format.
! */
! void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! bool all_privs, AclMode privileges, List *grantees,
! bool grant_option, DropBehavior behavior)
! {
! switch (objtype)
! {
! case ACL_OBJECT_RELATION:
! ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_DATABASE:
! ExecGrant_Database(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
! break;
! case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
! break;
! default:
! elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
! }
! }
!
! /*
! * objectNamesToOids
! *
! * Turn a list of object names of a given type into an Oid list.
! */
! static List *
! objectNamesToOids(GrantObjectType objtype, List *objnames)
! {
! List *objects = NIL;
! ListCell *cell;
!
! Assert(objnames != NIL);
!
! switch (objtype)
{
! case ACL_OBJECT_RELATION:
! foreach(cell, objnames)
! {
! Oid relOid;
! RangeVar *relvar = (RangeVar *) lfirst(cell);
!
! relOid = RangeVarGetRelid(relvar, false);
! objects = lappend_oid(objects, relOid);
! }
! break;
! case ACL_OBJECT_DATABASE:
! foreach(cell, objnames)
! {
! char *dbname = strVal(lfirst(cell));
! ScanKeyData entry[1];
! HeapScanDesc scan;
! HeapTuple tuple;
! Relation relation;
!
! relation = heap_open(DatabaseRelationId, AccessShareLock);
!
! /*
! * There's no syscache for pg_database, so we must
! * look the hard way.
! */
! 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)));
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! heap_close(relation, AccessShareLock);
!
! heap_endscan(scan);
! }
! break;
! case ACL_OBJECT_FUNCTION:
! foreach(cell, objnames)
! {
! FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
! Oid funcid;
!
! funcid = LookupFuncNameTypeNames(func->funcname,
! func->funcargs, false);
! objects = lappend_oid(objects, funcid);
! }
! break;
! case ACL_OBJECT_LANGUAGE:
! foreach(cell, objnames)
! {
! char *langname = strVal(lfirst(cell));
! 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)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! ReleaseSysCache(tuple);
! }
! break;
! case ACL_OBJECT_NAMESPACE:
! foreach (cell, objnames)
! {
! char *nspname = strVal(lfirst(cell));
! HeapTuple tuple;
!
! tuple = SearchSysCache(NAMESPACENAME,
! CStringGetDatum(nspname),
! 0, 0, 0);
! if (!HeapTupleIsValid(tuple))
! ereport(ERROR,
! (errcode(ERRCODE_UNDEFINED_SCHEMA),
! errmsg("schema \"%s\" does not exist", nspname)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! ReleaseSysCache(tuple);
! }
! break;
! case ACL_OBJECT_TABLESPACE:
! foreach (cell, objnames)
! {
! char *spcname = strVal(lfirst(cell));
! ScanKeyData entry[1];
! HeapScanDesc scan;
! HeapTuple tuple;
! Relation relation;
!
! relation = heap_open(TableSpaceRelationId, AccessShareLock);
!
! 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)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! heap_endscan(scan);
!
! heap_close(relation, AccessShareLock);
! }
! break;
! default:
! elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
! }
!
! return objects;
! }
!
! static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
! {
! Relation relation;
! ListCell *cell;
!
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_RELATION;
!
! relation = heap_open(RelationRelationId, RowExclusiveLock);
!
! foreach (cell, objects)
! {
! Oid relOid = lfirst_oid(cell);
Datum aclDatum;
+ Form_pg_class pg_class_tuple;
bool isNull;
AclMode avail_goptions;
AclMode this_privileges;
***************
*** 223,228 ****
--- 468,474 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
***************
*** 232,240 ****
Oid *oldmembers;
Oid *newmembers;
- /* open pg_class */
- relation = heap_open(RelationRelationId, RowExclusiveLock);
- relOid = RangeVarGetRelid(relvar, false);
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relOid),
0, 0, 0);
--- 478,483 ----
***************
*** 247,261 ****
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.
--- 490,503 ----
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);
}
/*
--- 527,533 ----
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));
}
/*
***************
*** 297,303 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 539,545 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 328,336 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 570,578 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 352,358 ****
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 594,600 ----
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 360,409 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_DATABASE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for database",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 602,630 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_DATABASE;
! relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
Datum aclDatum;
bool isNull;
***************
*** 421,438 ****
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);
/*
--- 642,664 ----
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
! /* There's no syscache for pg_database, so must look the hard way */
ScanKeyInit(&entry[0],
! ObjectIdAttributeNumber,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(datId));
! 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", datId);
!
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
/*
***************
*** 476,482 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 702,708 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 507,515 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 733,741 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 522,528 ****
replaces[Anum_pg_database_datacl - 1] = 'r';
values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 748,755 ----
replaces[Anum_pg_database_datacl - 1] = 'r';
values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 531,587 ****
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! 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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_FUNCTION;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for function",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 758,794 ----
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! systable_endscan(scan);
! pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_FUNCTION;
! relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
Datum aclDatum;
bool isNull;
***************
*** 591,596 ****
--- 798,804 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
***************
*** 600,613 ****
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);
/*
--- 808,819 ----
Oid *oldmembers;
Oid *newmembers;
tuple = SearchSysCache(PROCOID,
! ObjectIdGetDatum(funcId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for function %u", funcId);
!
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
/*
***************
*** 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)
--- 840,846 ----
*/
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)
***************
*** 651,657 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 857,863 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 682,690 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 888,896 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 697,703 ****
replaces[Anum_pg_proc_proacl - 1] = 'r';
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 903,910 ----
replaces[Anum_pg_proc_proacl - 1] = 'r';
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 705,712 ****
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(ProcedureRelationId, oid,
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 912,919 ----
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 714,761 ****
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;
privileges = ACL_ALL_RIGHTS_LANGUAGE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for language",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! foreach(i, stmt->objects)
{
! char *langname = strVal(lfirst(i));
! Relation relation;
! HeapTuple tuple;
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
--- 921,949 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_LANGUAGE;
! relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid langid = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
***************
*** 765,770 ****
--- 953,959 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
***************
*** 774,794 ****
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,
--- 963,982 ----
Oid *oldmembers;
Oid *newmembers;
! tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langid);
!
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,
***************
*** 834,840 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1022,1028 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 865,873 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1053,1061 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 880,886 ****
replaces[Anum_pg_language_lanacl - 1] = 'r';
values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1068,1075 ----
replaces[Anum_pg_language_lanacl - 1] = 'r';
values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 889,895 ****
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1078,1084 ----
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 897,944 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_NAMESPACE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for schema",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! foreach(i, stmt->objects)
{
! char *nspname = strVal(lfirst(i));
! Relation relation;
! HeapTuple tuple;
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
--- 1086,1114 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_NAMESPACE;
! relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
! Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
***************
*** 948,953 ****
--- 1118,1124 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_namespace];
char nulls[Natts_pg_namespace];
***************
*** 957,970 ****
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);
/*
--- 1128,1139 ----
Oid *oldmembers;
Oid *newmembers;
! tuple = SearchSysCache(NAMESPACEOID,
! ObjectIdGetDatum(nspid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for namespace %u", nspid);
!
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);
}
/*
--- 1166,1172 ----
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));
}
/*
***************
*** 1009,1015 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1178,1184 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 1040,1048 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1209,1217 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1055,1061 ****
replaces[Anum_pg_namespace_nspacl - 1] = 'r';
values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1224,1231 ----
replaces[Anum_pg_namespace_nspacl - 1] = 'r';
values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 1064,1070 ****
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1234,1240 ----
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1072,1121 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_TABLESPACE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_TABLESPACE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for tablespace",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 1242,1270 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_TABLESPACE;
! relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
! Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
Datum aclDatum;
bool isNull;
***************
*** 1133,1150 ****
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);
/*
--- 1282,1302 ----
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
! /* There's no syscache for pg_tablespace, so must look the hard way */
ScanKeyInit(&entry[0],
! ObjectIdAttributeNumber,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(tblId));
! scan = systable_beginscan(relation, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for tablespace %u", tblId);
!
pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
/*
***************
*** 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);
}
/*
--- 1328,1334 ----
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));
}
/*
***************
*** 1188,1194 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1340,1346 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 1219,1227 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1371,1379 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1386,1393 ----
replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 1242,1260 ****
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(TableSpaceRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! pfree(new_acl);
! heap_endscan(scan);
! heap_close(relation, RowExclusiveLock);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
}
--- 1395,1414 ----
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! systable_endscan(scan);
! pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
***************
*** 1537,1543 ****
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
--- 1691,1697 ----
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
***************
*** 1558,1565 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
! tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
--- 1712,1720 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
***************
*** 1588,1594 ****
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
--- 1743,1749 ----
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
***************
*** 1801,1807 ****
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
--- 1956,1962 ----
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
***************
*** 1829,1836 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
! tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
--- 1984,1992 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
***************
*** 1859,1865 ****
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
--- 2015,2021 ----
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
***************
*** 2091,2097 ****
{
Relation pg_tablespace;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
--- 2247,2253 ----
{
Relation pg_tablespace;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
***************
*** 2105,2113 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
! spctuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
--- 2261,2270 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! spctuple = systable_getnext(scan);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
***************
*** 2116,2122 ****
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
! heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return has_privs_of_role(roleid, spcowner);
--- 2273,2279 ----
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
! systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return has_privs_of_role(roleid, spcowner);
***************
*** 2159,2165 ****
{
Relation pg_database;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple dbtuple;
Oid dba;
--- 2316,2322 ----
{
Relation pg_database;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple dbtuple;
Oid dba;
***************
*** 2173,2181 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
! dbtuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(dbtuple))
ereport(ERROR,
--- 2330,2339 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
! SnapshotNow, 1, entry);
! dbtuple = systable_getnext(scan);
if (!HeapTupleIsValid(dbtuple))
ereport(ERROR,
***************
*** 2184,2190 ****
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
! heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
return has_privs_of_role(roleid, dba);
--- 2342,2348 ----
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
! systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return has_privs_of_role(roleid, dba);
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 19 Nov 2005 21:38:13 -0000
***************
*** 163,168 ****
--- 163,220 ----
}
/*
+ * objectIsInternalDependency -- return whether the specified object
+ * is listed as an internal dependency for some other object.
+ *
+ * This is used to implement DROP/REASSIGN OWNED. We cannot invoke
+ * performDeletion blindly, because it may try to drop or modify an internal-
+ * dependent object 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 19 Nov 2005 21:30:50 -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,1305 ----
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;
+ GrantObjectType objtype;
+
+ /* Shouldn't happen */
+ case SHARED_DEPENDENCY_PIN:
+ case SHARED_DEPENDENCY_INVALID:
+ elog(ERROR, "unexpected dependency type");
+ break;
+ case SHARED_DEPENDENCY_ACL:
+ switch (sdepForm->classid)
+ {
+ case RelationRelationId:
+ objtype = ACL_OBJECT_RELATION;
+ break;
+ case DatabaseRelationId:
+ objtype = ACL_OBJECT_DATABASE;
+ break;
+ case ProcedureRelationId:
+ objtype = ACL_OBJECT_FUNCTION;
+ break;
+ case LanguageRelationId:
+ objtype = ACL_OBJECT_LANGUAGE;
+ break;
+ case NamespaceRelationId:
+ objtype = ACL_OBJECT_NAMESPACE;
+ break;
+ case TableSpaceRelationId:
+ objtype = ACL_OBJECT_TABLESPACE;
+ break;
+ default:
+ elog(ERROR, "unexpected object type %d",
+ sdepForm->classid);
+ /* keep compiler quiet */
+ objtype = (GrantObjectType) 0;
+ break;
+ }
+
+ ExecGrantStmt_oids(false, objtype,
+ list_make1_oid(sdepForm->objid), true,
+ ACL_NO_RIGHTS, list_make1_oid(roleid),
+ false, DROP_CASCADE);
+ 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;
+
+ /*
+ * If there's a regular (non-shared) dependency on this
+ * object marked with DEPENDENCY_INTERNAL, skip this
+ * object. We will alter the referencer object instead.
+ */
+ if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid))
+ 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 19 Nov 2005 21:53:49 -0000
***************
*** 30,35 ****
--- 30,37 ----
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+ static void AlterConversionOwner_internal(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,197 ****
--- 191,230 ----
errmsg("conversion \"%s\" does not exist",
NameListToString(name))));
+ AlterConversionOwner_internal(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_internal(rel, conversionOid, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ /*
+ * AlterConversionOwner_internal
+ *
+ * Internal routine for changing the owner. rel must be pg_conversion, already
+ * open and suitably locked; it will not be closed.
+ */
+ static void
+ AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
+ {
+ Form_pg_conversion convForm;
+ HeapTuple tup;
+
+ Assert(RelationGetRelid(rel) == ConversionRelationId);
+
tup = SearchSysCacheCopy(CONOID,
ObjectIdGetDatum(conversionOid),
0, 0, 0);
***************
*** 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);
--- 239,253 ----
*/
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);
}
--- 275,279 ----
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 19 Nov 2005 21:30:50 -0000
***************
*** 55,60 ****
--- 55,61 ----
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+ static void AlterFunctionOwner_internal(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_internal(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_internal(rel, tup, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ static void
+ AlterFunctionOwner_internal(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 19 Nov 2005 21:47:10 -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_internal(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)) /* shouldn't happen */
! elog(ERROR, "cache lookup failed for opclass %u", opcOid);
!
! AlterOpClassOwner_internal(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_internal(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_internal(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 19 Nov 2005 21:52:12 -0000
***************
*** 48,53 ****
--- 48,55 ----
#include "utils/syscache.h"
+ static void AlterOperatorOwner_internal(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_internal(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,308 ----
Oid newOwnerId)
{
Oid operOid;
Relation rel;
rel = heap_open(OperatorRelationId, RowExclusiveLock);
operOid = LookupOperNameTypeNames(name, typeName1, typeName2,
false);
+ AlterOperatorOwner_internal(rel, operOid, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ static void
+ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
+ {
+ HeapTuple tup;
+ AclResult aclresult;
+ Form_pg_operator oprForm;
+
+ Assert(RelationGetRelid(rel) == OperatorRelationId);
+
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);
--- 323,329 ----
/* 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);
-
}
--- 350,354 ----
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 19 Nov 2005 21:49:42 -0000
***************
*** 31,36 ****
--- 31,38 ----
#include "utils/syscache.h"
+ static void AlterSchemaOwner_internal(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_internal(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,327 ----
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema \"%s\" does not exist", name)));
+
+ AlterSchemaOwner_internal(tup, rel, newOwnerId);
+
+ ReleaseSysCache(tup);
+
+ heap_close(rel, RowExclusiveLock);
+ }
+
+ static void
+ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
+ {
+ Form_pg_namespace nspForm;
+
+ Assert(tup->t_tableOid == NamespaceRelationId);
+ Assert(RelationGetRelid(rel) == NamespaceRelationId);
+
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);
--- 342,348 ----
/* 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);
}
--- 395,398 ----
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 153,158 ****
--- 153,159 ----
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
DeallocateStmt PrepareStmt ExecuteStmt
+ DropOwnedStmt ReassignOwnedStmt
%type <node> 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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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")));
***************
*** 689,696 ****
break;
/*
! * ******************************** object creation / destruction ********************************
! *
*/
case T_DefineStmt:
{
--- 691,697 ----
break;
/*
! * **************** object creation / destruction ******************
*/
case T_DefineStmt:
{
***************
*** 983,988 ****
--- 984,997 ----
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 ****
--- 1650,1663 ----
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 221,226 ****
--- 221,229 ----
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
+ extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
+ List *objects, bool all_privs, AclMode privileges,
+ List *grantees, bool grant_option, DropBehavior behavior);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
Index: src/test/regress/expected/dependency.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/dependency.out,v
retrieving revision 1.2
diff -c -r1.2 dependency.out
*** src/test/regress/expected/dependency.out 4 Aug 2005 01:09:29 -0000 1.2
--- src/test/regress/expected/dependency.out 19 Nov 2005 22:40:31 -0000
***************
*** 38,43 ****
--- 38,113 ----
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
ERROR: role "regression_user3" cannot be dropped because some objects depend on it
+ \set VERBOSITY default
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;
+ -- Test DROP OWNED
+ CREATE USER regression_user0;
+ CREATE USER regression_user1;
+ CREATE USER regression_user2;
+ SET SESSION AUTHORIZATION regression_user0;
+ -- permission denied
+ DROP OWNED BY regression_user1;
+ ERROR: permission denied to drop objects
+ DROP OWNED BY regression_user0, regression_user2;
+ ERROR: permission denied to drop objects
+ REASSIGN OWNED BY regression_user0 TO regression_user1;
+ ERROR: permission denied to reassign objects
+ REASSIGN OWNED BY regression_user1 TO regression_user0;
+ ERROR: permission denied to reassign objects
+ -- this one is allowed
+ DROP OWNED BY regression_user0;
+ CREATE TABLE deptest1 ();
+ GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ NOTICE: CREATE TABLE will create implicit sequence "deptest_a_seq" for serial column "deptest.a"
+ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" for table "deptest"
+ GRANT ALL ON deptest1 TO regression_user2;
+ RESET SESSION AUTHORIZATION;
+ \z deptest1
+ Access privileges for database "regression"
+ Schema | Name | Type | Access privileges
+ --------+----------+-------+----------------------------------------------------------------------------------------------------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdRxt/regression_user0,regression_user1=a*r*w*d*R*x*t*/regression_user0,regression_user2=arwdRxt/regression_user1}
+ (1 row)
+
+ DROP OWNED BY regression_user1;
+ -- all grants revoked
+ \z deptest1
+ Access privileges for database "regression"
+ Schema | Name | Type | Access privileges
+ --------+----------+-------+---------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdRxt/regression_user0}
+ (1 row)
+
+ -- table was dropped
+ \d deptest
+ -- Test REASSIGN OWNED
+ GRANT ALL ON deptest1 TO regression_user1;
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ NOTICE: CREATE TABLE will create implicit sequence "deptest_a_seq" for serial column "deptest.a"
+ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" for table "deptest"
+ RESET SESSION AUTHORIZATION;
+ REASSIGN OWNED BY regression_user1 TO regression_user2;
+ \dt deptest
+ List of relations
+ Schema | Name | Type | Owner
+ --------+---------+-------+------------------
+ public | deptest | table | regression_user2
+ (1 row)
+
+ -- doesn't work: grant still exists
+ DROP USER regression_user1;
+ ERROR: role "regression_user1" cannot be dropped because some objects depend on it
+ DETAIL: access to table deptest1
+ DROP OWNED BY regression_user1;
+ DROP USER regression_user1;
+ \set VERBOSITY terse
+ DROP USER regression_user2;
+ ERROR: role "regression_user2" cannot be dropped because some objects depend on it
+ DROP OWNED BY regression_user2, regression_user0;
+ DROP USER regression_user2;
+ DROP USER regression_user0;
Index: src/test/regress/sql/dependency.sql
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/sql/dependency.sql,v
retrieving revision 1.2
diff -c -r1.2 dependency.sql
*** src/test/regress/sql/dependency.sql 4 Aug 2005 01:09:29 -0000 1.2
--- src/test/regress/sql/dependency.sql 19 Nov 2005 22:39:36 -0000
***************
*** 39,44 ****
--- 39,93 ----
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
+ \set VERBOSITY default
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;
+
+ -- Test DROP OWNED
+ CREATE USER regression_user0;
+ CREATE USER regression_user1;
+ CREATE USER regression_user2;
+ SET SESSION AUTHORIZATION regression_user0;
+ -- permission denied
+ DROP OWNED BY regression_user1;
+ DROP OWNED BY regression_user0, regression_user2;
+ REASSIGN OWNED BY regression_user0 TO regression_user1;
+ REASSIGN OWNED BY regression_user1 TO regression_user0;
+ -- this one is allowed
+ DROP OWNED BY regression_user0;
+
+ CREATE TABLE deptest1 ();
+ GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
+
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ GRANT ALL ON deptest1 TO regression_user2;
+ RESET SESSION AUTHORIZATION;
+ \z deptest1
+
+ DROP OWNED BY regression_user1;
+ -- all grants revoked
+ \z deptest1
+ -- table was dropped
+ \d deptest
+
+ -- Test REASSIGN OWNED
+ GRANT ALL ON deptest1 TO regression_user1;
+
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ RESET SESSION AUTHORIZATION;
+
+ REASSIGN OWNED BY regression_user1 TO regression_user2;
+ \dt deptest
+ -- doesn't work: grant still exists
+ DROP USER regression_user1;
+ DROP OWNED BY regression_user1;
+ DROP USER regression_user1;
+
+ \set VERBOSITY terse
+ DROP USER regression_user2;
+ DROP OWNED BY regression_user2, regression_user0;
+ DROP USER regression_user2;
+ DROP USER regression_user0;
Attachments:
[text/plain] drop-owned-4.patch (107.0K, 2-drop-owned-4.patch)
download | inline diff:
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 70,75 ****
--- 70,76 ----
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
+ <!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
***************
*** 93,98 ****
--- 94,100 ----
<!entity notify system "notify.sgml">
<!entity prepare system "prepare.sgml">
<!entity prepareTransaction system "prepare_transaction.sgml">
+ <!entity reassignOwned system "reassign_owned.sgml">
<!entity reindex system "reindex.sgml">
<!entity releaseSavepoint system "release_savepoint.sgml">
<!entity reset system "reset.sgml">
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 19 Nov 2005 21:36:24 -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,66 ----
#include "utils/syscache.h"
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
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.
--- 110,119 ----
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.
***************
*** 151,221 ****
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",
(int) stmt->objtype);
}
- }
-
-
- static void
- ExecuteGrantStmt_Relation(GrantStmt *stmt)
- {
- AclMode privileges;
- bool all_privs;
- ListCell *i;
if (stmt->privileges == NIL)
{
all_privs = true;
! privileges = ACL_ALL_RIGHTS_RELATION;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
! foreach(i, stmt->privileges)
{
! char *privname = strVal(lfirst(i));
AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for table",
privilege_to_string(priv))));
privileges |= priv;
}
}
! 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;
--- 160,466 ----
void
ExecuteGrantStmt(GrantStmt *stmt)
{
+ List *objects;
+ List *grantees = NIL;
+ AclMode privileges;
+ ListCell *cell;
+ bool all_privs;
+ AclMode all_privileges = (AclMode) 0;
+ char *errormsg = NULL;
+
+ /*
+ * Convert the PrivGrantee list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if an empty role name is
+ * detected (which is what the grammar uses if PUBLIC is found), so
+ * downstream there shouldn't be any additional work needed to support this
+ * case.
+ */
+ 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));
+ }
+
+ /*
+ * Convert stmt->privileges, a textual list, into an AclMode bitmask
+ * appropiate for the given object class.
+ */
switch (stmt->objtype)
{
case ACL_OBJECT_RELATION:
! all_privileges = ACL_ALL_RIGHTS_RELATION;
! errormsg = _("invalid privilege type %s for table");
break;
case ACL_OBJECT_DATABASE:
! all_privileges = ACL_ALL_RIGHTS_DATABASE;
! errormsg = _("invalid privilege type %s for database");
break;
case ACL_OBJECT_FUNCTION:
! all_privileges = ACL_ALL_RIGHTS_FUNCTION;
! errormsg = _("invalid privilege type %s for function");
break;
case ACL_OBJECT_LANGUAGE:
! all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
! errormsg = _("invalid privilege type %s for language");
break;
case ACL_OBJECT_NAMESPACE:
! all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
! errormsg = _("invalid privilege type %s for namespace");
break;
case ACL_OBJECT_TABLESPACE:
! all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
! errormsg = _("invalid privilege type %s for tablespace");
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
all_privs = true;
! privileges = all_privileges;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
! foreach(cell, stmt->privileges)
{
! char *privname = strVal(lfirst(cell));
AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) all_privileges))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg(errormsg,
privilege_to_string(priv))));
+
privileges |= priv;
}
}
! /* Turn the list of object names into an Oid list */
! objects = objectNamesToOids(stmt->objtype, stmt->objects);
!
! ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! privileges, grantees, stmt->grant_option,
! stmt->behavior);
! }
!
! /*
! * ExecGrantStmt_oids
! *
! * "Internal" entrypoint for granting and revoking privileges. The arguments
! * it receives are lists of Oids or have been otherwise converted from text
! * format to internal format.
! */
! void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! bool all_privs, AclMode privileges, List *grantees,
! bool grant_option, DropBehavior behavior)
! {
! switch (objtype)
! {
! case ACL_OBJECT_RELATION:
! ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_DATABASE:
! ExecGrant_Database(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
! break;
! case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
! break;
! case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
! break;
! default:
! elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
! }
! }
!
! /*
! * objectNamesToOids
! *
! * Turn a list of object names of a given type into an Oid list.
! */
! static List *
! objectNamesToOids(GrantObjectType objtype, List *objnames)
! {
! List *objects = NIL;
! ListCell *cell;
!
! Assert(objnames != NIL);
!
! switch (objtype)
{
! case ACL_OBJECT_RELATION:
! foreach(cell, objnames)
! {
! Oid relOid;
! RangeVar *relvar = (RangeVar *) lfirst(cell);
!
! relOid = RangeVarGetRelid(relvar, false);
! objects = lappend_oid(objects, relOid);
! }
! break;
! case ACL_OBJECT_DATABASE:
! foreach(cell, objnames)
! {
! char *dbname = strVal(lfirst(cell));
! ScanKeyData entry[1];
! HeapScanDesc scan;
! HeapTuple tuple;
! Relation relation;
!
! relation = heap_open(DatabaseRelationId, AccessShareLock);
!
! /*
! * There's no syscache for pg_database, so we must
! * look the hard way.
! */
! 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)));
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! heap_close(relation, AccessShareLock);
!
! heap_endscan(scan);
! }
! break;
! case ACL_OBJECT_FUNCTION:
! foreach(cell, objnames)
! {
! FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
! Oid funcid;
!
! funcid = LookupFuncNameTypeNames(func->funcname,
! func->funcargs, false);
! objects = lappend_oid(objects, funcid);
! }
! break;
! case ACL_OBJECT_LANGUAGE:
! foreach(cell, objnames)
! {
! char *langname = strVal(lfirst(cell));
! 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)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! ReleaseSysCache(tuple);
! }
! break;
! case ACL_OBJECT_NAMESPACE:
! foreach (cell, objnames)
! {
! char *nspname = strVal(lfirst(cell));
! HeapTuple tuple;
!
! tuple = SearchSysCache(NAMESPACENAME,
! CStringGetDatum(nspname),
! 0, 0, 0);
! if (!HeapTupleIsValid(tuple))
! ereport(ERROR,
! (errcode(ERRCODE_UNDEFINED_SCHEMA),
! errmsg("schema \"%s\" does not exist", nspname)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! ReleaseSysCache(tuple);
! }
! break;
! case ACL_OBJECT_TABLESPACE:
! foreach (cell, objnames)
! {
! char *spcname = strVal(lfirst(cell));
! ScanKeyData entry[1];
! HeapScanDesc scan;
! HeapTuple tuple;
! Relation relation;
!
! relation = heap_open(TableSpaceRelationId, AccessShareLock);
!
! 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)));
!
! objects = lappend_oid(objects, HeapTupleGetOid(tuple));
!
! heap_endscan(scan);
!
! heap_close(relation, AccessShareLock);
! }
! break;
! default:
! elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
! }
!
! return objects;
! }
!
! static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
! {
! Relation relation;
! ListCell *cell;
!
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_RELATION;
!
! relation = heap_open(RelationRelationId, RowExclusiveLock);
!
! foreach (cell, objects)
! {
! Oid relOid = lfirst_oid(cell);
Datum aclDatum;
+ Form_pg_class pg_class_tuple;
bool isNull;
AclMode avail_goptions;
AclMode this_privileges;
***************
*** 223,228 ****
--- 468,474 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
***************
*** 232,240 ****
Oid *oldmembers;
Oid *newmembers;
- /* open pg_class */
- relation = heap_open(RelationRelationId, RowExclusiveLock);
- relOid = RangeVarGetRelid(relvar, false);
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relOid),
0, 0, 0);
--- 478,483 ----
***************
*** 247,261 ****
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.
--- 490,503 ----
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);
}
/*
--- 527,533 ----
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));
}
/*
***************
*** 297,303 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 539,545 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 328,336 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 570,578 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 352,358 ****
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 594,600 ----
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 360,409 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_DATABASE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for database",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 602,630 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_DATABASE;
! relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
Datum aclDatum;
bool isNull;
***************
*** 421,438 ****
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);
/*
--- 642,664 ----
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
! /* There's no syscache for pg_database, so must look the hard way */
ScanKeyInit(&entry[0],
! ObjectIdAttributeNumber,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(datId));
! 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", datId);
!
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
/*
***************
*** 476,482 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 702,708 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 507,515 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 733,741 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 522,528 ****
replaces[Anum_pg_database_datacl - 1] = 'r';
values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 748,755 ----
replaces[Anum_pg_database_datacl - 1] = 'r';
values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 531,587 ****
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! 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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_FUNCTION;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for function",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 758,794 ----
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! systable_endscan(scan);
! pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_FUNCTION;
! relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
Datum aclDatum;
bool isNull;
***************
*** 591,596 ****
--- 798,804 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
***************
*** 600,613 ****
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);
/*
--- 808,819 ----
Oid *oldmembers;
Oid *newmembers;
tuple = SearchSysCache(PROCOID,
! ObjectIdGetDatum(funcId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for function %u", funcId);
!
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
/*
***************
*** 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)
--- 840,846 ----
*/
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)
***************
*** 651,657 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 857,863 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 682,690 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 888,896 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 697,703 ****
replaces[Anum_pg_proc_proacl - 1] = 'r';
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 903,910 ----
replaces[Anum_pg_proc_proacl - 1] = 'r';
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 705,712 ****
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(ProcedureRelationId, oid,
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 912,919 ----
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 714,761 ****
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;
privileges = ACL_ALL_RIGHTS_LANGUAGE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for language",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! foreach(i, stmt->objects)
{
! char *langname = strVal(lfirst(i));
! Relation relation;
! HeapTuple tuple;
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
--- 921,949 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_LANGUAGE;
! relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid langid = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
***************
*** 765,770 ****
--- 953,959 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
***************
*** 774,794 ****
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,
--- 963,982 ----
Oid *oldmembers;
Oid *newmembers;
! tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langid);
!
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,
***************
*** 834,840 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1022,1028 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 865,873 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1053,1061 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 880,886 ****
replaces[Anum_pg_language_lanacl - 1] = 'r';
values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1068,1075 ----
replaces[Anum_pg_language_lanacl - 1] = 'r';
values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 889,895 ****
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1078,1084 ----
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 897,944 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_NAMESPACE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for schema",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! foreach(i, stmt->objects)
{
! char *nspname = strVal(lfirst(i));
! Relation relation;
! HeapTuple tuple;
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
--- 1086,1114 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_NAMESPACE;
! relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
! Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
***************
*** 948,953 ****
--- 1118,1124 ----
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_namespace];
char nulls[Natts_pg_namespace];
***************
*** 957,970 ****
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);
/*
--- 1128,1139 ----
Oid *oldmembers;
Oid *newmembers;
! tuple = SearchSysCache(NAMESPACEOID,
! ObjectIdGetDatum(nspid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for namespace %u", nspid);
!
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);
}
/*
--- 1166,1172 ----
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));
}
/*
***************
*** 1009,1015 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1178,1184 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 1040,1048 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1209,1217 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1055,1061 ****
replaces[Anum_pg_namespace_nspacl - 1] = 'r';
values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1224,1231 ----
replaces[Anum_pg_namespace_nspacl - 1] = 'r';
values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 1064,1070 ****
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1234,1240 ----
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1072,1121 ****
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)
! {
! all_privs = true;
privileges = ACL_ALL_RIGHTS_TABLESPACE;
- }
- else
- {
- all_privs = false;
- privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
- {
- char *privname = strVal(lfirst(i));
- AclMode priv = string_to_privilege(privname);
! if (priv & ~((AclMode) ACL_ALL_RIGHTS_TABLESPACE))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_GRANT_OPERATION),
! errmsg("invalid privilege type %s for tablespace",
! privilege_to_string(priv))));
! privileges |= priv;
! }
! }
! 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;
--- 1242,1270 ----
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
! Relation relation;
! ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
privileges = ACL_ALL_RIGHTS_TABLESPACE;
! relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
! Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
Datum aclDatum;
bool isNull;
***************
*** 1133,1150 ****
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);
/*
--- 1282,1302 ----
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
! /* There's no syscache for pg_tablespace, so must look the hard way */
ScanKeyInit(&entry[0],
! ObjectIdAttributeNumber,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(tblId));
! scan = systable_beginscan(relation, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for tablespace %u", tblId);
!
pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
/*
***************
*** 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);
}
/*
--- 1328,1334 ----
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));
}
/*
***************
*** 1188,1194 ****
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
--- 1340,1346 ----
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
***************
*** 1219,1227 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! 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);
--- 1371,1379 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
--- 1386,1393 ----
replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
! newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
! nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
***************
*** 1242,1260 ****
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(TableSpaceRelationId, HeapTupleGetOid(tuple),
! ownerId, stmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! pfree(new_acl);
! heap_endscan(scan);
! heap_close(relation, RowExclusiveLock);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
}
--- 1395,1414 ----
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
! updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
! systable_endscan(scan);
! pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
***************
*** 1537,1543 ****
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
--- 1691,1697 ----
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
***************
*** 1558,1565 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
! tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
--- 1712,1720 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
***************
*** 1588,1594 ****
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
--- 1743,1749 ----
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
***************
*** 1801,1807 ****
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
--- 1956,1962 ----
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
***************
*** 1829,1836 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
! tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
--- 1984,1992 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
***************
*** 1859,1865 ****
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
--- 2015,2021 ----
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
! systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
***************
*** 2091,2097 ****
{
Relation pg_tablespace;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
--- 2247,2253 ----
{
Relation pg_tablespace;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
***************
*** 2105,2113 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
! spctuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
--- 2261,2270 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
! scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
! SnapshotNow, 1, entry);
! spctuple = systable_getnext(scan);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
***************
*** 2116,2122 ****
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
! heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return has_privs_of_role(roleid, spcowner);
--- 2273,2279 ----
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
! systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return has_privs_of_role(roleid, spcowner);
***************
*** 2159,2165 ****
{
Relation pg_database;
ScanKeyData entry[1];
! HeapScanDesc scan;
HeapTuple dbtuple;
Oid dba;
--- 2316,2322 ----
{
Relation pg_database;
ScanKeyData entry[1];
! SysScanDesc scan;
HeapTuple dbtuple;
Oid dba;
***************
*** 2173,2181 ****
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
! dbtuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(dbtuple))
ereport(ERROR,
--- 2330,2339 ----
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
! scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
! SnapshotNow, 1, entry);
! dbtuple = systable_getnext(scan);
if (!HeapTupleIsValid(dbtuple))
ereport(ERROR,
***************
*** 2184,2190 ****
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
! heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
return has_privs_of_role(roleid, dba);
--- 2342,2348 ----
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
! systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return has_privs_of_role(roleid, dba);
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 19 Nov 2005 21:38:13 -0000
***************
*** 163,168 ****
--- 163,220 ----
}
/*
+ * objectIsInternalDependency -- return whether the specified object
+ * is listed as an internal dependency for some other object.
+ *
+ * This is used to implement DROP/REASSIGN OWNED. We cannot invoke
+ * performDeletion blindly, because it may try to drop or modify an internal-
+ * dependent object 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 19 Nov 2005 21:30:50 -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,1305 ----
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;
+ GrantObjectType objtype;
+
+ /* Shouldn't happen */
+ case SHARED_DEPENDENCY_PIN:
+ case SHARED_DEPENDENCY_INVALID:
+ elog(ERROR, "unexpected dependency type");
+ break;
+ case SHARED_DEPENDENCY_ACL:
+ switch (sdepForm->classid)
+ {
+ case RelationRelationId:
+ objtype = ACL_OBJECT_RELATION;
+ break;
+ case DatabaseRelationId:
+ objtype = ACL_OBJECT_DATABASE;
+ break;
+ case ProcedureRelationId:
+ objtype = ACL_OBJECT_FUNCTION;
+ break;
+ case LanguageRelationId:
+ objtype = ACL_OBJECT_LANGUAGE;
+ break;
+ case NamespaceRelationId:
+ objtype = ACL_OBJECT_NAMESPACE;
+ break;
+ case TableSpaceRelationId:
+ objtype = ACL_OBJECT_TABLESPACE;
+ break;
+ default:
+ elog(ERROR, "unexpected object type %d",
+ sdepForm->classid);
+ /* keep compiler quiet */
+ objtype = (GrantObjectType) 0;
+ break;
+ }
+
+ ExecGrantStmt_oids(false, objtype,
+ list_make1_oid(sdepForm->objid), true,
+ ACL_NO_RIGHTS, list_make1_oid(roleid),
+ false, DROP_CASCADE);
+ 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;
+
+ /*
+ * If there's a regular (non-shared) dependency on this
+ * object marked with DEPENDENCY_INTERNAL, skip this
+ * object. We will alter the referencer object instead.
+ */
+ if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid))
+ 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 19 Nov 2005 21:53:49 -0000
***************
*** 30,35 ****
--- 30,37 ----
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+ static void AlterConversionOwner_internal(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,197 ****
--- 191,230 ----
errmsg("conversion \"%s\" does not exist",
NameListToString(name))));
+ AlterConversionOwner_internal(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_internal(rel, conversionOid, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ /*
+ * AlterConversionOwner_internal
+ *
+ * Internal routine for changing the owner. rel must be pg_conversion, already
+ * open and suitably locked; it will not be closed.
+ */
+ static void
+ AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
+ {
+ Form_pg_conversion convForm;
+ HeapTuple tup;
+
+ Assert(RelationGetRelid(rel) == ConversionRelationId);
+
tup = SearchSysCacheCopy(CONOID,
ObjectIdGetDatum(conversionOid),
0, 0, 0);
***************
*** 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);
--- 239,253 ----
*/
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);
}
--- 275,279 ----
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 19 Nov 2005 21:30:50 -0000
***************
*** 55,60 ****
--- 55,61 ----
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+ static void AlterFunctionOwner_internal(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_internal(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_internal(rel, tup, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ static void
+ AlterFunctionOwner_internal(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 19 Nov 2005 21:47:10 -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_internal(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)) /* shouldn't happen */
! elog(ERROR, "cache lookup failed for opclass %u", opcOid);
!
! AlterOpClassOwner_internal(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_internal(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_internal(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 19 Nov 2005 21:52:12 -0000
***************
*** 48,53 ****
--- 48,55 ----
#include "utils/syscache.h"
+ static void AlterOperatorOwner_internal(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_internal(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,308 ----
Oid newOwnerId)
{
Oid operOid;
Relation rel;
rel = heap_open(OperatorRelationId, RowExclusiveLock);
operOid = LookupOperNameTypeNames(name, typeName1, typeName2,
false);
+ AlterOperatorOwner_internal(rel, operOid, newOwnerId);
+
+ heap_close(rel, NoLock);
+ }
+
+ static void
+ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
+ {
+ HeapTuple tup;
+ AclResult aclresult;
+ Form_pg_operator oprForm;
+
+ Assert(RelationGetRelid(rel) == OperatorRelationId);
+
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);
--- 323,329 ----
/* 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);
-
}
--- 350,354 ----
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 19 Nov 2005 21:49:42 -0000
***************
*** 31,36 ****
--- 31,38 ----
#include "utils/syscache.h"
+ static void AlterSchemaOwner_internal(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_internal(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,327 ----
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema \"%s\" does not exist", name)));
+
+ AlterSchemaOwner_internal(tup, rel, newOwnerId);
+
+ ReleaseSysCache(tup);
+
+ heap_close(rel, RowExclusiveLock);
+ }
+
+ static void
+ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
+ {
+ Form_pg_namespace nspForm;
+
+ Assert(tup->t_tableOid == NamespaceRelationId);
+ Assert(RelationGetRelid(rel) == NamespaceRelationId);
+
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);
--- 342,348 ----
/* 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);
}
--- 395,398 ----
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 153,158 ****
--- 153,159 ----
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
DeallocateStmt PrepareStmt ExecuteStmt
+ DropOwnedStmt ReassignOwnedStmt
%type <node> 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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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")));
***************
*** 689,696 ****
break;
/*
! * ******************************** object creation / destruction ********************************
! *
*/
case T_DefineStmt:
{
--- 691,697 ----
break;
/*
! * **************** object creation / destruction ******************
*/
case T_DefineStmt:
{
***************
*** 983,988 ****
--- 984,997 ----
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 ****
--- 1650,1663 ----
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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -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 19 Nov 2005 21:30:50 -0000
***************
*** 221,226 ****
--- 221,229 ----
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
+ extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
+ List *objects, bool all_privs, AclMode privileges,
+ List *grantees, bool grant_option, DropBehavior behavior);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
Index: src/test/regress/expected/dependency.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/dependency.out,v
retrieving revision 1.2
diff -c -r1.2 dependency.out
*** src/test/regress/expected/dependency.out 4 Aug 2005 01:09:29 -0000 1.2
--- src/test/regress/expected/dependency.out 19 Nov 2005 22:40:31 -0000
***************
*** 38,43 ****
--- 38,113 ----
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
ERROR: role "regression_user3" cannot be dropped because some objects depend on it
+ \set VERBOSITY default
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;
+ -- Test DROP OWNED
+ CREATE USER regression_user0;
+ CREATE USER regression_user1;
+ CREATE USER regression_user2;
+ SET SESSION AUTHORIZATION regression_user0;
+ -- permission denied
+ DROP OWNED BY regression_user1;
+ ERROR: permission denied to drop objects
+ DROP OWNED BY regression_user0, regression_user2;
+ ERROR: permission denied to drop objects
+ REASSIGN OWNED BY regression_user0 TO regression_user1;
+ ERROR: permission denied to reassign objects
+ REASSIGN OWNED BY regression_user1 TO regression_user0;
+ ERROR: permission denied to reassign objects
+ -- this one is allowed
+ DROP OWNED BY regression_user0;
+ CREATE TABLE deptest1 ();
+ GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ NOTICE: CREATE TABLE will create implicit sequence "deptest_a_seq" for serial column "deptest.a"
+ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" for table "deptest"
+ GRANT ALL ON deptest1 TO regression_user2;
+ RESET SESSION AUTHORIZATION;
+ \z deptest1
+ Access privileges for database "regression"
+ Schema | Name | Type | Access privileges
+ --------+----------+-------+----------------------------------------------------------------------------------------------------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdRxt/regression_user0,regression_user1=a*r*w*d*R*x*t*/regression_user0,regression_user2=arwdRxt/regression_user1}
+ (1 row)
+
+ DROP OWNED BY regression_user1;
+ -- all grants revoked
+ \z deptest1
+ Access privileges for database "regression"
+ Schema | Name | Type | Access privileges
+ --------+----------+-------+---------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdRxt/regression_user0}
+ (1 row)
+
+ -- table was dropped
+ \d deptest
+ -- Test REASSIGN OWNED
+ GRANT ALL ON deptest1 TO regression_user1;
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ NOTICE: CREATE TABLE will create implicit sequence "deptest_a_seq" for serial column "deptest.a"
+ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" for table "deptest"
+ RESET SESSION AUTHORIZATION;
+ REASSIGN OWNED BY regression_user1 TO regression_user2;
+ \dt deptest
+ List of relations
+ Schema | Name | Type | Owner
+ --------+---------+-------+------------------
+ public | deptest | table | regression_user2
+ (1 row)
+
+ -- doesn't work: grant still exists
+ DROP USER regression_user1;
+ ERROR: role "regression_user1" cannot be dropped because some objects depend on it
+ DETAIL: access to table deptest1
+ DROP OWNED BY regression_user1;
+ DROP USER regression_user1;
+ \set VERBOSITY terse
+ DROP USER regression_user2;
+ ERROR: role "regression_user2" cannot be dropped because some objects depend on it
+ DROP OWNED BY regression_user2, regression_user0;
+ DROP USER regression_user2;
+ DROP USER regression_user0;
Index: src/test/regress/sql/dependency.sql
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/sql/dependency.sql,v
retrieving revision 1.2
diff -c -r1.2 dependency.sql
*** src/test/regress/sql/dependency.sql 4 Aug 2005 01:09:29 -0000 1.2
--- src/test/regress/sql/dependency.sql 19 Nov 2005 22:39:36 -0000
***************
*** 39,44 ****
--- 39,93 ----
ALTER TABLE deptest OWNER TO regression_user3;
DROP USER regression_user3;
+ \set VERBOSITY default
-- if we drop the object, we can drop the user too
DROP TABLE deptest;
DROP USER regression_user3;
+
+ -- Test DROP OWNED
+ CREATE USER regression_user0;
+ CREATE USER regression_user1;
+ CREATE USER regression_user2;
+ SET SESSION AUTHORIZATION regression_user0;
+ -- permission denied
+ DROP OWNED BY regression_user1;
+ DROP OWNED BY regression_user0, regression_user2;
+ REASSIGN OWNED BY regression_user0 TO regression_user1;
+ REASSIGN OWNED BY regression_user1 TO regression_user0;
+ -- this one is allowed
+ DROP OWNED BY regression_user0;
+
+ CREATE TABLE deptest1 ();
+ GRANT ALL ON deptest1 TO regression_user1 WITH GRANT OPTION;
+
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ GRANT ALL ON deptest1 TO regression_user2;
+ RESET SESSION AUTHORIZATION;
+ \z deptest1
+
+ DROP OWNED BY regression_user1;
+ -- all grants revoked
+ \z deptest1
+ -- table was dropped
+ \d deptest
+
+ -- Test REASSIGN OWNED
+ GRANT ALL ON deptest1 TO regression_user1;
+
+ SET SESSION AUTHORIZATION regression_user1;
+ CREATE TABLE deptest (a serial primary key, b text);
+ RESET SESSION AUTHORIZATION;
+
+ REASSIGN OWNED BY regression_user1 TO regression_user2;
+ \dt deptest
+ -- doesn't work: grant still exists
+ DROP USER regression_user1;
+ DROP OWNED BY regression_user1;
+ DROP USER regression_user1;
+
+ \set VERBOSITY terse
+ DROP USER regression_user2;
+ DROP OWNED BY regression_user2, regression_user0;
+ DROP USER regression_user2;
+ DROP USER regression_user0;
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: DROP OWNED again
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
@ 2005-11-21 13:33 ` Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
0 siblings, 1 reply; 10+ messages in thread
From: Alvaro Herrera @ 2005-11-21 13:33 UTC (permalink / raw)
To: Tom Lane <[email protected]>; Patches <[email protected]>
Alvaro Herrera wrote:
> I have added the regression tests in this new version, which I'll apply
> on monday barring any objections. (I do not attach the SGML files
> because these didn't change since the last post.)
Applied.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
^ permalink raw reply [nested|flat] 10+ messages in thread
* aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
@ 2005-11-21 15:16 ` Alvaro Herrera <[email protected]>
2005-11-21 16:34 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
2005-12-01 13:36 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
0 siblings, 2 replies; 10+ messages in thread
From: Alvaro Herrera @ 2005-11-21 15:16 UTC (permalink / raw)
To: Tom Lane <[email protected]>; Patches <[email protected]>
I intend to apply later today the attached patch in order to reduce some
code duplication in aclchk.c and clean a bit the API I just introduced
in the previous patch. This reduces aclchk.c from 2377 lines to 2206.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.121
diff -c -r1.121 aclchk.c
*** src/backend/catalog/aclchk.c 21 Nov 2005 12:49:30 -0000 1.121
--- src/backend/catalog/aclchk.c 21 Nov 2005 15:05:19 -0000
***************
*** 42,69 ****
#include "utils/syscache.h"
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
static AclMode string_to_privilege(const char *privname);
static const char *privilege_to_string(AclMode privilege);
#ifdef ACLDEBUG
--- 42,62 ----
#include "utils/syscache.h"
! static void ExecGrant_Relation(InternalGrant *grantStmt);
! static void ExecGrant_Database(InternalGrant *grantStmt);
! static void ExecGrant_Function(InternalGrant *grantStmt);
! static void ExecGrant_Language(InternalGrant *grantStmt);
! static void ExecGrant_Namespace(InternalGrant *grantStmt);
! static void ExecGrant_Tablespace(InternalGrant *grantStmt);
+ static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
static AclMode string_to_privilege(const char *privname);
static const char *privilege_to_string(AclMode privilege);
+ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
+ bool all_privs, AclMode privileges,
+ Oid objectId, Oid grantorId,
+ AclMode whole_mask,
+ AclObjectKind objkind, char *objname);
#ifdef ACLDEBUG
***************
*** 160,172 ****
void
ExecuteGrantStmt(GrantStmt *stmt)
{
! List *objects;
! List *grantees = NIL;
! AclMode privileges;
ListCell *cell;
! bool all_privs;
! AclMode all_privileges = (AclMode) 0;
! char *errormsg = NULL;
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
--- 153,174 ----
void
ExecuteGrantStmt(GrantStmt *stmt)
{
! InternalGrant istmt;
ListCell *cell;
! char *errormsg;
! AclMode all_privileges;
!
! /*
! * Turn the regular GrantStmt into the InternalGrant form.
! */
! istmt.is_grant = stmt->is_grant;
! istmt.objtype = stmt->objtype;
! istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
! /* all_privs to be filled below */
! /* privileges to be filled below */
! /* grantees to be filled below */
! istmt.grant_option = stmt->grant_option;
! istmt.behavior = stmt->behavior;
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
***************
*** 180,194 ****
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));
}
/*
! * Convert stmt->privileges, a textual list, into an AclMode bitmask
! * appropiate for the given object class.
*/
switch (stmt->objtype)
{
--- 182,196 ----
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
if (grantee->rolname == NULL)
! istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
else
! istmt.grantees =
! lappend_oid(istmt.grantees,
! get_roleid_checked(grantee->rolname));
}
/*
! * Convert stmt->privileges, a textual list, into an AclMode bitmask.
*/
switch (stmt->objtype)
{
***************
*** 217,235 ****
errormsg = _("invalid privilege type %s for tablespace");
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
! all_privs = true;
! privileges = all_privileges;
}
else
{
! all_privs = false;
! privileges = ACL_NO_RIGHTS;
foreach(cell, stmt->privileges)
{
char *privname = strVal(lfirst(cell));
--- 219,244 ----
errormsg = _("invalid privilege type %s for tablespace");
break;
default:
+ /* keep compiler quiet */
+ all_privileges = ACL_NO_RIGHTS;
+ errormsg = NULL;
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
! istmt.all_privs = true;
! /*
! * will be turned into ACL_ALL_RIGHTS_* by the internal routines
! * depending on the object type
! */
! istmt.privileges = ACL_NO_RIGHTS;
}
else
{
! istmt.all_privs = false;
! istmt.privileges = ACL_NO_RIGHTS;
foreach(cell, stmt->privileges)
{
char *privname = strVal(lfirst(cell));
***************
*** 241,301 ****
errmsg(errormsg,
privilege_to_string(priv))));
! privileges |= priv;
}
}
! /* Turn the list of object names into an Oid list */
! objects = objectNamesToOids(stmt->objtype, stmt->objects);
!
! ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! privileges, grantees, stmt->grant_option,
! stmt->behavior);
}
/*
* ExecGrantStmt_oids
*
! * "Internal" entrypoint for granting and revoking privileges. The arguments
! * it receives are lists of Oids or have been otherwise converted from text
! * format to internal format.
*/
void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! bool all_privs, AclMode privileges, List *grantees,
! bool grant_option, DropBehavior behavior)
{
! switch (objtype)
{
case ACL_OBJECT_RELATION:
! ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_DATABASE:
! ExecGrant_Database(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
break;
case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
}
}
--- 250,293 ----
errmsg(errormsg,
privilege_to_string(priv))));
! istmt.privileges |= priv;
}
}
! ExecGrantStmt_oids(&istmt);
}
/*
* ExecGrantStmt_oids
*
! * "Internal" entrypoint for granting and revoking privileges.
*/
void
! ExecGrantStmt_oids(InternalGrant *istmt)
{
! switch (istmt->objtype)
{
case ACL_OBJECT_RELATION:
! ExecGrant_Relation(istmt);
break;
case ACL_OBJECT_DATABASE:
! ExecGrant_Database(istmt);
break;
case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(istmt);
break;
case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(istmt);
break;
case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(istmt);
break;
case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(istmt);
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) istmt->objtype);
}
}
***************
*** 443,462 ****
return objects;
}
static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_RELATION;
relation = heap_open(RelationRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid relOid = lfirst_oid(cell);
Datum aclDatum;
--- 435,513 ----
return objects;
}
+ /*
+ * Restrict the privileges to what we can actually grant, and emit
+ * the standards-mandated warning and error messages.
+ */
+ static AclMode
+ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
+ AclMode privileges, Oid objectId, Oid grantorId,
+ AclMode whole_mask, AclObjectKind objkind,
+ char *objname)
+ {
+ AclMode this_privileges;
+
+ /*
+ * If we found no grant options, consider whether to issue a hard
+ * error. Per spec, having any privilege at all on the object will
+ * get you by here.
+ */
+ if (avail_goptions == ACL_NO_RIGHTS)
+ {
+ if (pg_class_aclmask(objectId,
+ grantorId,
+ whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ ACLMASK_ANY) == ACL_NO_RIGHTS)
+ aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
+ }
+
+ /*
+ * Restrict the operation to what we can actually grant or revoke, and
+ * issue a warning if appropriate. (For REVOKE this isn't quite what
+ * the spec says to do: the spec seems to want a warning only if no
+ * privilege bits actually change in the ACL. In practice that
+ * behavior seems much too noisy, as well as inconsistent with the
+ * GRANT case.)
+ */
+ this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+ if (is_grant)
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("no privileges were granted")));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("not all privileges were granted")));
+ }
+ else
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("no privileges could be revoked")));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("not all privileges could be revoked")));
+ }
+
+ return this_privileges;
+ }
+
static void
! ExecGrant_Relation(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_RELATION;
relation = heap_open(RelationRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid relOid = lfirst_oid(cell);
Datum aclDatum;
***************
*** 511,566 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_class_aclmask(relOid,
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 562,581 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! relOid, grantorId,
! ACL_ALL_RIGHTS_RELATION, ACL_KIND_CLASS,
! NameStr(pg_class_tuple->relname));
/*
* Generate new ACL.
***************
*** 570,578 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 585,593 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 594,600 ****
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 609,615 ----
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 610,628 ****
}
static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_DATABASE;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
--- 625,641 ----
}
static void
! ExecGrant_Database(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
***************
*** 674,729 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_database_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
! ACLMASK_ANY) == ACL_NO_RIGHTS)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
! NameStr(pg_database_tuple->datname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 687,706 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! datId, grantorId, ACL_ALL_RIGHTS_DATABASE,
! ACL_KIND_DATABASE,
! NameStr(pg_database_tuple->datname));
/*
* Generate new ACL.
***************
*** 733,741 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 710,718 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 758,764 ****
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 735,741 ----
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 774,792 ****
}
static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_FUNCTION;
relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
--- 751,767 ----
}
static void
! ExecGrant_Function(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
***************
*** 829,884 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! 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)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
! NameStr(pg_proc_tuple->proname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 804,824 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! funcId, grantorId,
! ACL_ALL_RIGHTS_FUNCTION,
! ACL_KIND_PROC,
! NameStr(pg_proc_tuple->proname));
/*
* Generate new ACL.
***************
*** 888,896 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 828,836 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 913,919 ****
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 853,859 ----
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 929,949 ****
}
static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_LANGUAGE;
relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid langid = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
--- 869,887 ----
}
static void
! ExecGrant_Language(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
! Oid langId = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
***************
*** 964,973 ****
Oid *newmembers;
tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langid);
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
--- 902,911 ----
Oid *newmembers;
tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langId);
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
***************
*** 994,1049 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_language_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
! ACLMASK_ANY) == ACL_NO_RIGHTS)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
! NameStr(pg_language_tuple->lanname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 932,952 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! langId, grantorId,
! ACL_ALL_RIGHTS_LANGUAGE,
! ACL_KIND_LANGUAGE,
! NameStr(pg_language_tuple->lanname));
/*
* Generate new ACL.
***************
*** 1053,1061 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 956,964 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1078,1084 ****
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 981,987 ----
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1094,1112 ****
}
static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_NAMESPACE;
relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
--- 997,1013 ----
}
static void
! ExecGrant_Namespace(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, istmt->objects)
{
Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
***************
*** 1150,1205 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_namespace_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 1051,1071 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! nspid, grantorId,
! ACL_ALL_RIGHTS_NAMESPACE,
! ACL_KIND_NAMESPACE,
! NameStr(pg_namespace_tuple->nspname));
/*
* Generate new ACL.
***************
*** 1209,1217 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 1075,1083 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1100,1106 ----
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1250,1268 ****
}
static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_TABLESPACE;
relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
--- 1116,1132 ----
}
static void
! ExecGrant_Tablespace(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, istmt->objects)
{
Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
***************
*** 1312,1367 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_tablespace_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 1176,1196 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! tblId, grantorId,
! ACL_ALL_RIGHTS_TABLESPACE,
! ACL_KIND_TABLESPACE,
! NameStr(pg_tablespace_tuple->spcname));
/*
* Generate new ACL.
***************
*** 1371,1379 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 1200,1208 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1396,1402 ****
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1225,1231 ----
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.4
diff -c -r1.4 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c 21 Nov 2005 12:49:30 -0000 1.4
--- src/backend/catalog/pg_shdepend.c 21 Nov 2005 15:08:16 -0000
***************
*** 1122,1127 ****
--- 1122,1128 ----
{
ObjectAddress obj;
GrantObjectType objtype;
+ InternalGrant istmt;
/* Shouldn't happen */
case SHARED_DEPENDENCY_PIN:
***************
*** 1132,1153 ****
switch (sdepForm->classid)
{
case RelationRelationId:
! objtype = ACL_OBJECT_RELATION;
break;
case DatabaseRelationId:
! objtype = ACL_OBJECT_DATABASE;
break;
case ProcedureRelationId:
! objtype = ACL_OBJECT_FUNCTION;
break;
case LanguageRelationId:
! objtype = ACL_OBJECT_LANGUAGE;
break;
case NamespaceRelationId:
! objtype = ACL_OBJECT_NAMESPACE;
break;
case TableSpaceRelationId:
! objtype = ACL_OBJECT_TABLESPACE;
break;
default:
elog(ERROR, "unexpected object type %d",
--- 1133,1154 ----
switch (sdepForm->classid)
{
case RelationRelationId:
! istmt.objtype = ACL_OBJECT_RELATION;
break;
case DatabaseRelationId:
! istmt.objtype = ACL_OBJECT_DATABASE;
break;
case ProcedureRelationId:
! istmt.objtype = ACL_OBJECT_FUNCTION;
break;
case LanguageRelationId:
! istmt.objtype = ACL_OBJECT_LANGUAGE;
break;
case NamespaceRelationId:
! istmt.objtype = ACL_OBJECT_NAMESPACE;
break;
case TableSpaceRelationId:
! istmt.objtype = ACL_OBJECT_TABLESPACE;
break;
default:
elog(ERROR, "unexpected object type %d",
***************
*** 1156,1166 ****
objtype = (GrantObjectType) 0;
break;
}
! ExecGrantStmt_oids(false, objtype,
! list_make1_oid(sdepForm->objid), true,
! ACL_NO_RIGHTS, list_make1_oid(roleid),
! false, DROP_CASCADE);
break;
case SHARED_DEPENDENCY_OWNER:
/*
--- 1157,1171 ----
objtype = (GrantObjectType) 0;
break;
}
+ istmt.is_grant = false;
+ istmt.objects = list_make1_oid(sdepForm->objid);
+ istmt.all_privs = true;
+ istmt.privileges = ACL_NO_RIGHTS;
+ istmt.grantees = list_make1_oid(roleid);
+ istmt.grant_option = false;
+ istmt.behavior = DROP_CASCADE;
! ExecGrantStmt_oids(&istmt);
break;
case SHARED_DEPENDENCY_OWNER:
/*
Index: src/include/utils/acl.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v
retrieving revision 1.89
diff -c -r1.89 acl.h
*** src/include/utils/acl.h 21 Nov 2005 12:49:33 -0000 1.89
--- src/include/utils/acl.h 21 Nov 2005 14:32:59 -0000
***************
*** 182,187 ****
--- 182,207 ----
} AclObjectKind;
/*
+ * The information about one Grant/Revoke statement, in internal format: object
+ * and grantees names have been turned into Oids, the privilege list is an
+ * AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
+ * all_privs is true, it will be internally turned into the right kind of
+ * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
+ * InternalGrant struct!)
+ */
+ typedef struct
+ {
+ bool is_grant;
+ GrantObjectType objtype;
+ List *objects;
+ bool all_privs;
+ AclMode privileges;
+ List *grantees;
+ bool grant_option;
+ DropBehavior behavior;
+ } InternalGrant;
+
+ /*
* routines used internally
*/
extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
***************
*** 221,229 ****
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
! List *objects, bool all_privs, AclMode privileges,
! List *grantees, bool grant_option, DropBehavior behavior);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
--- 241,247 ----
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(InternalGrant *istmt);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
Attachments:
[text/plain] aclchk-refactor-1.patch (44.2K, 2-aclchk-refactor-1.patch)
download | inline diff:
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.121
diff -c -r1.121 aclchk.c
*** src/backend/catalog/aclchk.c 21 Nov 2005 12:49:30 -0000 1.121
--- src/backend/catalog/aclchk.c 21 Nov 2005 15:05:19 -0000
***************
*** 42,69 ****
#include "utils/syscache.h"
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
static AclMode string_to_privilege(const char *privname);
static const char *privilege_to_string(AclMode privilege);
#ifdef ACLDEBUG
--- 42,62 ----
#include "utils/syscache.h"
! static void ExecGrant_Relation(InternalGrant *grantStmt);
! static void ExecGrant_Database(InternalGrant *grantStmt);
! static void ExecGrant_Function(InternalGrant *grantStmt);
! static void ExecGrant_Language(InternalGrant *grantStmt);
! static void ExecGrant_Namespace(InternalGrant *grantStmt);
! static void ExecGrant_Tablespace(InternalGrant *grantStmt);
+ static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
static AclMode string_to_privilege(const char *privname);
static const char *privilege_to_string(AclMode privilege);
+ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
+ bool all_privs, AclMode privileges,
+ Oid objectId, Oid grantorId,
+ AclMode whole_mask,
+ AclObjectKind objkind, char *objname);
#ifdef ACLDEBUG
***************
*** 160,172 ****
void
ExecuteGrantStmt(GrantStmt *stmt)
{
! List *objects;
! List *grantees = NIL;
! AclMode privileges;
ListCell *cell;
! bool all_privs;
! AclMode all_privileges = (AclMode) 0;
! char *errormsg = NULL;
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
--- 153,174 ----
void
ExecuteGrantStmt(GrantStmt *stmt)
{
! InternalGrant istmt;
ListCell *cell;
! char *errormsg;
! AclMode all_privileges;
!
! /*
! * Turn the regular GrantStmt into the InternalGrant form.
! */
! istmt.is_grant = stmt->is_grant;
! istmt.objtype = stmt->objtype;
! istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
! /* all_privs to be filled below */
! /* privileges to be filled below */
! /* grantees to be filled below */
! istmt.grant_option = stmt->grant_option;
! istmt.behavior = stmt->behavior;
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
***************
*** 180,194 ****
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));
}
/*
! * Convert stmt->privileges, a textual list, into an AclMode bitmask
! * appropiate for the given object class.
*/
switch (stmt->objtype)
{
--- 182,196 ----
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
if (grantee->rolname == NULL)
! istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
else
! istmt.grantees =
! lappend_oid(istmt.grantees,
! get_roleid_checked(grantee->rolname));
}
/*
! * Convert stmt->privileges, a textual list, into an AclMode bitmask.
*/
switch (stmt->objtype)
{
***************
*** 217,235 ****
errormsg = _("invalid privilege type %s for tablespace");
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
! all_privs = true;
! privileges = all_privileges;
}
else
{
! all_privs = false;
! privileges = ACL_NO_RIGHTS;
foreach(cell, stmt->privileges)
{
char *privname = strVal(lfirst(cell));
--- 219,244 ----
errormsg = _("invalid privilege type %s for tablespace");
break;
default:
+ /* keep compiler quiet */
+ all_privileges = ACL_NO_RIGHTS;
+ errormsg = NULL;
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
}
if (stmt->privileges == NIL)
{
! istmt.all_privs = true;
! /*
! * will be turned into ACL_ALL_RIGHTS_* by the internal routines
! * depending on the object type
! */
! istmt.privileges = ACL_NO_RIGHTS;
}
else
{
! istmt.all_privs = false;
! istmt.privileges = ACL_NO_RIGHTS;
foreach(cell, stmt->privileges)
{
char *privname = strVal(lfirst(cell));
***************
*** 241,301 ****
errmsg(errormsg,
privilege_to_string(priv))));
! privileges |= priv;
}
}
! /* Turn the list of object names into an Oid list */
! objects = objectNamesToOids(stmt->objtype, stmt->objects);
!
! ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! privileges, grantees, stmt->grant_option,
! stmt->behavior);
}
/*
* ExecGrantStmt_oids
*
! * "Internal" entrypoint for granting and revoking privileges. The arguments
! * it receives are lists of Oids or have been otherwise converted from text
! * format to internal format.
*/
void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! bool all_privs, AclMode privileges, List *grantees,
! bool grant_option, DropBehavior behavior)
{
! switch (objtype)
{
case ACL_OBJECT_RELATION:
! ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_DATABASE:
! ExecGrant_Database(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(is_grant, objects, all_privs, privileges,
! grantees, grant_option, behavior);
break;
case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
break;
case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(is_grant, objects, all_privs,
! privileges, grantees, grant_option,
! behavior);
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) objtype);
}
}
--- 250,293 ----
errmsg(errormsg,
privilege_to_string(priv))));
! istmt.privileges |= priv;
}
}
! ExecGrantStmt_oids(&istmt);
}
/*
* ExecGrantStmt_oids
*
! * "Internal" entrypoint for granting and revoking privileges.
*/
void
! ExecGrantStmt_oids(InternalGrant *istmt)
{
! switch (istmt->objtype)
{
case ACL_OBJECT_RELATION:
! ExecGrant_Relation(istmt);
break;
case ACL_OBJECT_DATABASE:
! ExecGrant_Database(istmt);
break;
case ACL_OBJECT_FUNCTION:
! ExecGrant_Function(istmt);
break;
case ACL_OBJECT_LANGUAGE:
! ExecGrant_Language(istmt);
break;
case ACL_OBJECT_NAMESPACE:
! ExecGrant_Namespace(istmt);
break;
case ACL_OBJECT_TABLESPACE:
! ExecGrant_Tablespace(istmt);
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! (int) istmt->objtype);
}
}
***************
*** 443,462 ****
return objects;
}
static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_RELATION;
relation = heap_open(RelationRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid relOid = lfirst_oid(cell);
Datum aclDatum;
--- 435,513 ----
return objects;
}
+ /*
+ * Restrict the privileges to what we can actually grant, and emit
+ * the standards-mandated warning and error messages.
+ */
+ static AclMode
+ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
+ AclMode privileges, Oid objectId, Oid grantorId,
+ AclMode whole_mask, AclObjectKind objkind,
+ char *objname)
+ {
+ AclMode this_privileges;
+
+ /*
+ * If we found no grant options, consider whether to issue a hard
+ * error. Per spec, having any privilege at all on the object will
+ * get you by here.
+ */
+ if (avail_goptions == ACL_NO_RIGHTS)
+ {
+ if (pg_class_aclmask(objectId,
+ grantorId,
+ whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ ACLMASK_ANY) == ACL_NO_RIGHTS)
+ aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
+ }
+
+ /*
+ * Restrict the operation to what we can actually grant or revoke, and
+ * issue a warning if appropriate. (For REVOKE this isn't quite what
+ * the spec says to do: the spec seems to want a warning only if no
+ * privilege bits actually change in the ACL. In practice that
+ * behavior seems much too noisy, as well as inconsistent with the
+ * GRANT case.)
+ */
+ this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+ if (is_grant)
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("no privileges were granted")));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("not all privileges were granted")));
+ }
+ else
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("no privileges could be revoked")));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("not all privileges could be revoked")));
+ }
+
+ return this_privileges;
+ }
+
static void
! ExecGrant_Relation(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_RELATION;
relation = heap_open(RelationRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid relOid = lfirst_oid(cell);
Datum aclDatum;
***************
*** 511,566 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_class_aclmask(relOid,
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 562,581 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! relOid, grantorId,
! ACL_ALL_RIGHTS_RELATION, ACL_KIND_CLASS,
! NameStr(pg_class_tuple->relname));
/*
* Generate new ACL.
***************
*** 570,578 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 585,593 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 594,600 ****
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 609,615 ----
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 610,628 ****
}
static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_DATABASE;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
--- 625,641 ----
}
static void
! ExecGrant_Database(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
***************
*** 674,729 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_database_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
! ACLMASK_ANY) == ACL_NO_RIGHTS)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
! NameStr(pg_database_tuple->datname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 687,706 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! datId, grantorId, ACL_ALL_RIGHTS_DATABASE,
! ACL_KIND_DATABASE,
! NameStr(pg_database_tuple->datname));
/*
* Generate new ACL.
***************
*** 733,741 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 710,718 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 758,764 ****
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 735,741 ----
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 774,792 ****
}
static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_FUNCTION;
relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
--- 751,767 ----
}
static void
! ExecGrant_Function(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
***************
*** 829,884 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! 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)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
! NameStr(pg_proc_tuple->proname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 804,824 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! funcId, grantorId,
! ACL_ALL_RIGHTS_FUNCTION,
! ACL_KIND_PROC,
! NameStr(pg_proc_tuple->proname));
/*
* Generate new ACL.
***************
*** 888,896 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 828,836 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 913,919 ****
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 853,859 ----
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 929,949 ****
}
static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_LANGUAGE;
relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, objects)
{
! Oid langid = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
--- 869,887 ----
}
static void
! ExecGrant_Language(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
relation = heap_open(LanguageRelationId, RowExclusiveLock);
! foreach (cell, istmt->objects)
{
! Oid langId = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
***************
*** 964,973 ****
Oid *newmembers;
tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langid);
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
--- 902,911 ----
Oid *newmembers;
tuple = SearchSysCache(LANGOID,
! ObjectIdGetDatum(langId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
! elog(ERROR, "cache lookup failed for language %u", langId);
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
***************
*** 994,1049 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_language_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
! ACLMASK_ANY) == ACL_NO_RIGHTS)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
! NameStr(pg_language_tuple->lanname));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 932,952 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! langId, grantorId,
! ACL_ALL_RIGHTS_LANGUAGE,
! ACL_KIND_LANGUAGE,
! NameStr(pg_language_tuple->lanname));
/*
* Generate new ACL.
***************
*** 1053,1061 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 956,964 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1078,1084 ****
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 981,987 ----
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1094,1112 ****
}
static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_NAMESPACE;
relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
--- 997,1013 ----
}
static void
! ExecGrant_Namespace(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
relation = heap_open(NamespaceRelationId, RowExclusiveLock);
! foreach(cell, istmt->objects)
{
Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
***************
*** 1150,1205 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
*/
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_namespace_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
! */
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 1051,1071 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! nspid, grantorId,
! ACL_ALL_RIGHTS_NAMESPACE,
! ACL_KIND_NAMESPACE,
! NameStr(pg_namespace_tuple->nspname));
/*
* Generate new ACL.
***************
*** 1209,1217 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 1075,1083 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1100,1106 ----
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
***************
*** 1250,1268 ****
}
static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! AclMode privileges, List *grantees, bool grant_option,
! DropBehavior behavior)
{
Relation relation;
ListCell *cell;
! if (all_privs && privileges == ACL_NO_RIGHTS)
! privileges = ACL_ALL_RIGHTS_TABLESPACE;
relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, objects)
{
Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
--- 1116,1132 ----
}
static void
! ExecGrant_Tablespace(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
! foreach(cell, istmt->objects)
{
Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
***************
*** 1312,1367 ****
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * If we found no grant options, consider whether to issue a hard
! * error. Per spec, having any privilege at all on the object will
! * get you by here.
! */
! if (avail_goptions == ACL_NO_RIGHTS)
! {
! if (pg_tablespace_aclmask(HeapTupleGetOid(tuple),
! grantorId,
! 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));
! }
!
! /*
! * Restrict the operation to what we can actually grant or revoke, and
! * issue a warning if appropriate. (For REVOKE this isn't quite what
! * the spec says to do: the spec seems to want a warning only if no
! * privilege bits actually change in the ACL. In practice that
! * behavior seems much too noisy, as well as inconsistent with the
! * GRANT case.)
*/
! this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! if (is_grant)
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("no privileges were granted")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! errmsg("not all privileges were granted")));
! }
! else
! {
! if (this_privileges == 0)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("no privileges could be revoked")));
! else if (!all_privs && this_privileges != privileges)
! ereport(WARNING,
! (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! errmsg("not all privileges could be revoked")));
! }
/*
* Generate new ACL.
--- 1176,1196 ----
old_acl = DatumGetAclPCopy(aclDatum);
/* Determine ID to do the grant as, and available grant options */
! select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
! * Restrict the privileges to what we can actually grant, and emit
! * the standards-mandated warning and error messages.
*/
! this_privileges =
! restrict_and_check_grant(istmt->is_grant, avail_goptions,
! istmt->all_privs, istmt->privileges,
! tblId, grantorId,
! ACL_ALL_RIGHTS_TABLESPACE,
! ACL_KIND_TABLESPACE,
! NameStr(pg_tablespace_tuple->spcname));
/*
* Generate new ACL.
***************
*** 1371,1379 ****
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, is_grant,
! grant_option, behavior,
! grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
--- 1200,1208 ----
*/
noldmembers = aclmembers(old_acl, &oldmembers);
! new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! istmt->grant_option, istmt->behavior,
! istmt->grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1396,1402 ****
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
--- 1225,1231 ----
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId,
! ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.4
diff -c -r1.4 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c 21 Nov 2005 12:49:30 -0000 1.4
--- src/backend/catalog/pg_shdepend.c 21 Nov 2005 15:08:16 -0000
***************
*** 1122,1127 ****
--- 1122,1128 ----
{
ObjectAddress obj;
GrantObjectType objtype;
+ InternalGrant istmt;
/* Shouldn't happen */
case SHARED_DEPENDENCY_PIN:
***************
*** 1132,1153 ****
switch (sdepForm->classid)
{
case RelationRelationId:
! objtype = ACL_OBJECT_RELATION;
break;
case DatabaseRelationId:
! objtype = ACL_OBJECT_DATABASE;
break;
case ProcedureRelationId:
! objtype = ACL_OBJECT_FUNCTION;
break;
case LanguageRelationId:
! objtype = ACL_OBJECT_LANGUAGE;
break;
case NamespaceRelationId:
! objtype = ACL_OBJECT_NAMESPACE;
break;
case TableSpaceRelationId:
! objtype = ACL_OBJECT_TABLESPACE;
break;
default:
elog(ERROR, "unexpected object type %d",
--- 1133,1154 ----
switch (sdepForm->classid)
{
case RelationRelationId:
! istmt.objtype = ACL_OBJECT_RELATION;
break;
case DatabaseRelationId:
! istmt.objtype = ACL_OBJECT_DATABASE;
break;
case ProcedureRelationId:
! istmt.objtype = ACL_OBJECT_FUNCTION;
break;
case LanguageRelationId:
! istmt.objtype = ACL_OBJECT_LANGUAGE;
break;
case NamespaceRelationId:
! istmt.objtype = ACL_OBJECT_NAMESPACE;
break;
case TableSpaceRelationId:
! istmt.objtype = ACL_OBJECT_TABLESPACE;
break;
default:
elog(ERROR, "unexpected object type %d",
***************
*** 1156,1166 ****
objtype = (GrantObjectType) 0;
break;
}
! ExecGrantStmt_oids(false, objtype,
! list_make1_oid(sdepForm->objid), true,
! ACL_NO_RIGHTS, list_make1_oid(roleid),
! false, DROP_CASCADE);
break;
case SHARED_DEPENDENCY_OWNER:
/*
--- 1157,1171 ----
objtype = (GrantObjectType) 0;
break;
}
+ istmt.is_grant = false;
+ istmt.objects = list_make1_oid(sdepForm->objid);
+ istmt.all_privs = true;
+ istmt.privileges = ACL_NO_RIGHTS;
+ istmt.grantees = list_make1_oid(roleid);
+ istmt.grant_option = false;
+ istmt.behavior = DROP_CASCADE;
! ExecGrantStmt_oids(&istmt);
break;
case SHARED_DEPENDENCY_OWNER:
/*
Index: src/include/utils/acl.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v
retrieving revision 1.89
diff -c -r1.89 acl.h
*** src/include/utils/acl.h 21 Nov 2005 12:49:33 -0000 1.89
--- src/include/utils/acl.h 21 Nov 2005 14:32:59 -0000
***************
*** 182,187 ****
--- 182,207 ----
} AclObjectKind;
/*
+ * The information about one Grant/Revoke statement, in internal format: object
+ * and grantees names have been turned into Oids, the privilege list is an
+ * AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
+ * all_privs is true, it will be internally turned into the right kind of
+ * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
+ * InternalGrant struct!)
+ */
+ typedef struct
+ {
+ bool is_grant;
+ GrantObjectType objtype;
+ List *objects;
+ bool all_privs;
+ AclMode privileges;
+ List *grantees;
+ bool grant_option;
+ DropBehavior behavior;
+ } InternalGrant;
+
+ /*
* routines used internally
*/
extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
***************
*** 221,229 ****
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
! List *objects, bool all_privs, AclMode privileges,
! List *grantees, bool grant_option, DropBehavior behavior);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
--- 241,247 ----
* prototypes for functions in aclchk.c
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(InternalGrant *istmt);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
@ 2005-11-21 16:34 ` Alvaro Herrera <[email protected]>
2005-11-21 16:57 ` Re: aclchk.c refactor Tom Lane <[email protected]>
1 sibling, 1 reply; 10+ messages in thread
From: Alvaro Herrera @ 2005-11-21 16:34 UTC (permalink / raw)
To: Tom Lane <[email protected]>; Patches <[email protected]>
Alvaro Herrera wrote:
> I intend to apply later today the attached patch in order to reduce some
> code duplication in aclchk.c and clean a bit the API I just introduced
> in the previous patch. This reduces aclchk.c from 2377 lines to 2206.
Of course, it would be much better if the proposed patch actually
worked, which it doesn't because there's a function call that I didn't
generalize: the code is calling pg_class_aclmask(), which of course only
works for relations.
Now I noticed that there are multiple functions pg_class_aclmask,
pg_database_aclmask, pg_language_aclmask, etc. Is there any objection
to making the exported routine expose the object type as an AclKind
parameter instead of having one function for each object type?
So instead of having
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
AclMode mask, AclMaskHow how);
We would have
extern AclMode pg_aclmask(AclKind objkind, Oid obj_oid, Oid roleid,
AclMode mask, AclMaskHow how);
And this would call the appropiate static function.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
2005-11-21 16:34 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
@ 2005-11-21 16:57 ` Tom Lane <[email protected]>
0 siblings, 0 replies; 10+ messages in thread
From: Tom Lane @ 2005-11-21 16:57 UTC (permalink / raw)
To: Alvaro Herrera <[email protected]>; +Cc: Patches <[email protected]>
Alvaro Herrera <[email protected]> writes:
> Now I noticed that there are multiple functions pg_class_aclmask,
> pg_database_aclmask, pg_language_aclmask, etc. Is there any objection
> to making the exported routine expose the object type as an AclKind
> parameter instead of having one function for each object type?
How about "in addition to" instead of "instead"? I see no reason to
impose extra notation and a level of indirection on the places that know
perfectly well which object type they are dealing with.
regards, tom lane
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
@ 2005-12-01 13:36 ` Alvaro Herrera <[email protected]>
2005-12-01 15:28 ` Re: [PATCHES] aclchk.c refactor Tom Lane <[email protected]>
1 sibling, 1 reply; 10+ messages in thread
From: Alvaro Herrera @ 2005-12-01 13:36 UTC (permalink / raw)
To: Tom Lane <[email protected]>; Patches <[email protected]>
Alvaro Herrera wrote:
> I intend to apply later today the attached patch in order to reduce some
> code duplication in aclchk.c and clean a bit the API I just introduced
> in the previous patch. This reduces aclchk.c from 2377 lines to 2206.
I applied this patch yesterday, but I did not receive the commit
message. However I do see it in the online archives.
Is there something fishy going on here, or just the mail was lost on its
way here?
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [PATCHES] aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
2005-12-01 13:36 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
@ 2005-12-01 15:28 ` Tom Lane <[email protected]>
2005-12-01 19:09 ` Re: [PATCHES] aclchk.c refactor Marc G. Fournier <[email protected]>
0 siblings, 1 reply; 10+ messages in thread
From: Tom Lane @ 2005-12-01 15:28 UTC (permalink / raw)
To: Alvaro Herrera <[email protected]>; +Cc: Marc Fournier <[email protected]>; pgsql-www
Alvaro Herrera <[email protected]> writes:
> I applied this patch yesterday, but I did not receive the commit
> message. However I do see it in the online archives.
> Is there something fishy going on here, or just the mail was lost on its
> way here?
[ checks mail logs... ] Hm, I never got a copy of this either:
http://archives.postgresql.org/pgsql-committers/2005-11/msg00609.php
There's definitely something flaky about pgsql-committers since the
server move. I still haven't seen anything about Michael's ecpg commits
of yesterday, either.
regards, tom lane
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [PATCHES] aclchk.c refactor
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Re: DROP OWNED again Tom Lane <[email protected]>
2005-11-19 22:55 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Re: DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
2005-12-01 13:36 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
2005-12-01 15:28 ` Re: [PATCHES] aclchk.c refactor Tom Lane <[email protected]>
@ 2005-12-01 19:09 ` Marc G. Fournier <[email protected]>
0 siblings, 0 replies; 10+ messages in thread
From: Marc G. Fournier @ 2005-12-01 19:09 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Alvaro Herrera <[email protected]>; pgsql-www
Everything should be good now ... had to change Michael and Niel over, and
just approved through their commits also ...
On Thu, 1 Dec 2005, Tom Lane wrote:
> Alvaro Herrera <[email protected]> writes:
>> I applied this patch yesterday, but I did not receive the commit
>> message. However I do see it in the online archives.
>
>> Is there something fishy going on here, or just the mail was lost on its
>> way here?
>
> [ checks mail logs... ] Hm, I never got a copy of this either:
> http://archives.postgresql.org/pgsql-committers/2005-11/msg00609.php
>
> There's definitely something flaky about pgsql-committers since the
> server move. I still haven't seen anything about Michael's ecpg commits
> of yesterday, either.
>
> regards, tom lane
>
>
----
Marc G. Fournier Hub.Org Networking Services (http://www.hub.org)
Email: [email protected] Yahoo!: yscrappy ICQ: 7615664
^ permalink raw reply [nested|flat] 10+ messages in thread
end of thread, other threads:[~2005-12-01 19:09 UTC | newest]
Thread overview: 10+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2005-11-18 19:54 DROP OWNED again Alvaro Herrera <[email protected]>
2005-11-19 00:59 ` Tom Lane <[email protected]>
2005-11-19 22:55 ` Alvaro Herrera <[email protected]>
2005-11-21 13:33 ` Alvaro Herrera <[email protected]>
2005-11-21 15:16 ` aclchk.c refactor Alvaro Herrera <[email protected]>
2005-11-21 16:34 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
2005-11-21 16:57 ` Re: aclchk.c refactor Tom Lane <[email protected]>
2005-12-01 13:36 ` Re: aclchk.c refactor Alvaro Herrera <[email protected]>
2005-12-01 15:28 ` Re: [PATCHES] aclchk.c refactor Tom Lane <[email protected]>
2005-12-01 19:09 ` Re: [PATCHES] aclchk.c refactor Marc G. Fournier <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox