<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.66 2005/07/29 15:13:11 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.67 2005/11/21 12:49:30 alvherre Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
<!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">
<!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">
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_owned.sgml,v 1.1 2005/11/21 12:49:30 alvherre Exp $
+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:
+-->
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/reassign_owned.sgml,v 1.1 2005/11/21 12:49:30 alvherre Exp $
+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:
+-->
<!-- reference.sgml
-$PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.56 2005/07/29 15:13:11 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.57 2005/11/21 12:49:30 alvherre Exp $
PostgreSQL Reference Manual
-->
&dropLanguage;
&dropOperator;
&dropOperatorClass;
+ &dropOwned;
&dropRole;
&dropRule;
&dropSchema;
¬ify;
&prepare;
&prepareTransaction;
+ &reassignOwned;
&reindex;
&releaseSavepoint;
&reset;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.120 2005/10/15 02:49:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.121 2005/11/21 12:49:30 alvherre Exp $
*
* NOTES
* See acl.h.
*/
#include "postgres.h"
+#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#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 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);
foreach(j, grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
- AclItem aclitem;
+ AclItem aclitem;
Acl *newer_acl;
- if (grantee->rolname)
- aclitem. ai_grantee = get_roleid_checked(grantee->rolname);
-
- else
- aclitem. ai_grantee = ACL_ID_PUBLIC;
+ aclitem.ai_grantee = lfirst_oid(j);
/*
* Grant options can only be granted to individual roles, not PUBLIC.
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:
- ExecuteGrantStmt_Relation(stmt);
+ all_privileges = ACL_ALL_RIGHTS_RELATION;
+ errormsg = _("invalid privilege type %s for table");
break;
case ACL_OBJECT_DATABASE:
- ExecuteGrantStmt_Database(stmt);
+ all_privileges = ACL_ALL_RIGHTS_DATABASE;
+ errormsg = _("invalid privilege type %s for database");
break;
case ACL_OBJECT_FUNCTION:
- ExecuteGrantStmt_Function(stmt);
+ all_privileges = ACL_ALL_RIGHTS_FUNCTION;
+ errormsg = _("invalid privilege type %s for function");
break;
case ACL_OBJECT_LANGUAGE:
- ExecuteGrantStmt_Language(stmt);
+ all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
+ errormsg = _("invalid privilege type %s for language");
break;
case ACL_OBJECT_NAMESPACE:
- ExecuteGrantStmt_Namespace(stmt);
+ all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ errormsg = _("invalid privilege type %s for namespace");
break;
case ACL_OBJECT_TABLESPACE:
- ExecuteGrantStmt_Tablespace(stmt);
+ all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
+ errormsg = _("invalid privilege type %s for tablespace");
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;
+ privileges = all_privileges;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
- foreach(i, stmt->privileges)
+ foreach(cell, stmt->privileges)
{
- char *privname = strVal(lfirst(i));
+ char *privname = strVal(lfirst(cell));
AclMode priv = string_to_privilege(privname);
- if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
+ if (priv & ~((AclMode) all_privileges))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
- errmsg("invalid privilege type %s for table",
+ errmsg(errormsg,
privilege_to_string(priv))));
+
privileges |= priv;
}
}
- foreach(i, stmt->objects)
+ /* 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)
{
- RangeVar *relvar = (RangeVar *) lfirst(i);
- Oid relOid;
- Relation relation;
- HeapTuple tuple;
- Form_pg_class pg_class_tuple;
+ 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;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
Oid *oldmembers;
Oid *newmembers;
- /* open pg_class */
- relation = heap_open(RelationRelationId, RowExclusiveLock);
- relOid = RangeVarGetRelid(relvar, false);
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relOid),
0, 0, 0);
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an index",
- relvar->relname)));
+ 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",
- relvar->relname)));
-
+ NameStr(pg_class_tuple->relname))));
/*
* Get owner ID and working copy of existing ACL. If there's no ACL,
* substitute the proper default.
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);
+ NameStr(pg_class_tuple->relname));
}
/*
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
- ownerId, stmt->is_grant,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
- heap_close(relation, RowExclusiveLock);
-
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
-ExecuteGrantStmt_Database(GrantStmt *stmt)
+ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
+ AclMode privileges, List *grantees, bool grant_option,
+ DropBehavior behavior)
{
- AclMode privileges;
- bool all_privs;
- ListCell *i;
+ Relation relation;
+ ListCell *cell;
- if (stmt->privileges == NIL)
- {
- all_privs = true;
+ if (all_privs && privileges == ACL_NO_RIGHTS)
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;
- }
- }
+ relation = heap_open(DatabaseRelationId, RowExclusiveLock);
- foreach(i, stmt->objects)
+ foreach (cell, objects)
{
- char *dbname = strVal(lfirst(i));
- Relation relation;
- ScanKeyData entry[1];
- HeapScanDesc scan;
- HeapTuple tuple;
+ Oid datId = lfirst_oid(cell);
Form_pg_database pg_database_tuple;
Datum aclDatum;
bool isNull;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
- relation = heap_open(DatabaseRelationId, RowExclusiveLock);
+ /* There's no syscache for pg_database, so 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);
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(datId));
+ scan = systable_beginscan(relation, DatabaseOidIndexId, true,
+ SnapshotNow, 1, entry);
+
+ tuple = systable_getnext(scan);
+
if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_DATABASE),
- errmsg("database \"%s\" does not exist", dbname)));
+ elog(ERROR, "could not find tuple for database %u", datId);
+
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
/*
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
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);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
- ownerId, stmt->is_grant,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
- pfree(new_acl);
-
- heap_endscan(scan);
+ systable_endscan(scan);
- heap_close(relation, RowExclusiveLock);
+ pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
-ExecuteGrantStmt_Function(GrantStmt *stmt)
+ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
+ AclMode privileges, List *grantees, bool grant_option,
+ DropBehavior behavior)
{
- AclMode privileges;
- bool all_privs;
- ListCell *i;
+ Relation relation;
+ ListCell *cell;
- if (stmt->privileges == NIL)
- {
- all_privs = true;
+ if (all_privs && privileges == ACL_NO_RIGHTS)
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;
- }
- }
+ relation = heap_open(ProcedureRelationId, RowExclusiveLock);
- foreach(i, stmt->objects)
+ foreach (cell, objects)
{
- FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
- Oid oid;
- Relation relation;
- HeapTuple tuple;
+ Oid funcId = lfirst_oid(cell);
Form_pg_proc pg_proc_tuple;
Datum aclDatum;
bool isNull;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
Oid *oldmembers;
Oid *newmembers;
- oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false);
-
- relation = heap_open(ProcedureRelationId, RowExclusiveLock);
tuple = SearchSysCache(PROCOID,
- ObjectIdGetDatum(oid),
+ ObjectIdGetDatum(funcId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for function %u", oid);
+ elog(ERROR, "cache lookup failed for function %u", funcId);
+
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
/*
*/
if (avail_goptions == ACL_NO_RIGHTS)
{
- if (pg_proc_aclmask(oid,
+ if (pg_proc_aclmask(funcId,
grantorId,
ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION),
ACLMASK_ANY) == ACL_NO_RIGHTS)
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
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);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
- updateAclDependencies(ProcedureRelationId, oid,
- ownerId, stmt->is_grant,
+ updateAclDependencies(ProcedureRelationId, funcId,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
- heap_close(relation, RowExclusiveLock);
-
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
-ExecuteGrantStmt_Language(GrantStmt *stmt)
+ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
+ AclMode privileges, List *grantees, bool grant_option,
+ DropBehavior behavior)
{
- AclMode privileges;
- bool all_privs;
- ListCell *i;
+ Relation relation;
+ ListCell *cell;
- if (stmt->privileges == NIL)
- {
- all_privs = true;
+ if (all_privs && privileges == ACL_NO_RIGHTS)
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;
- }
- }
+ relation = heap_open(LanguageRelationId, RowExclusiveLock);
- foreach(i, stmt->objects)
+ foreach (cell, objects)
{
- char *langname = strVal(lfirst(i));
- Relation relation;
- HeapTuple tuple;
+ Oid langid = lfirst_oid(cell);
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
Oid *oldmembers;
Oid *newmembers;
- relation = heap_open(LanguageRelationId, RowExclusiveLock);
- tuple = SearchSysCache(LANGNAME,
- PointerGetDatum(langname),
+ tuple = SearchSysCache(LANGOID,
+ ObjectIdGetDatum(langid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("language \"%s\" does not exist", langname)));
+ 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", langname),
- errhint("Only superusers may use untrusted languages.")));
+ 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,
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
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);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
- ownerId, stmt->is_grant,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
- heap_close(relation, RowExclusiveLock);
-
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
-ExecuteGrantStmt_Namespace(GrantStmt *stmt)
+ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
+ AclMode privileges, List *grantees, bool grant_option,
+ DropBehavior behavior)
{
- AclMode privileges;
- bool all_privs;
- ListCell *i;
+ Relation relation;
+ ListCell *cell;
- if (stmt->privileges == NIL)
- {
- all_privs = true;
+ if (all_privs && privileges == ACL_NO_RIGHTS)
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;
- }
- }
+ relation = heap_open(NamespaceRelationId, RowExclusiveLock);
- foreach(i, stmt->objects)
+ foreach(cell, objects)
{
- char *nspname = strVal(lfirst(i));
- Relation relation;
- HeapTuple tuple;
+ Oid nspid = lfirst_oid(cell);
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
+ HeapTuple tuple;
HeapTuple newtuple;
Datum values[Natts_pg_namespace];
char nulls[Natts_pg_namespace];
Oid *oldmembers;
Oid *newmembers;
- relation = heap_open(NamespaceRelationId, RowExclusiveLock);
- tuple = SearchSysCache(NAMESPACENAME,
- CStringGetDatum(nspname),
+ tuple = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(nspid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_SCHEMA),
- errmsg("schema \"%s\" does not exist", nspname)));
+ elog(ERROR, "cache lookup failed for namespace %u", nspid);
+
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
/*
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);
+ NameStr(pg_namespace_tuple->nspname));
}
/*
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
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);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
- ownerId, stmt->is_grant,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
pfree(new_acl);
- heap_close(relation, RowExclusiveLock);
-
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
static void
-ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
+ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
+ AclMode privileges, List *grantees, bool grant_option,
+ DropBehavior behavior)
{
- AclMode privileges;
- bool all_privs;
- ListCell *i;
+ Relation relation;
+ ListCell *cell;
- if (stmt->privileges == NIL)
- {
- all_privs = true;
+ if (all_privs && privileges == ACL_NO_RIGHTS)
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;
- }
- }
+ relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
- foreach(i, stmt->objects)
+ foreach(cell, objects)
{
- char *spcname = strVal(lfirst(i));
- Relation relation;
- ScanKeyData entry[1];
- HeapScanDesc scan;
- HeapTuple tuple;
+ Oid tblId = lfirst_oid(cell);
Form_pg_tablespace pg_tablespace_tuple;
Datum aclDatum;
bool isNull;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tuple;
- relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
+ /* There's no syscache for pg_tablespace, so must look the hard way */
ScanKeyInit(&entry[0],
- Anum_pg_tablespace_spcname,
- BTEqualStrategyNumber, F_NAMEEQ,
- CStringGetDatum(spcname));
- scan = heap_beginscan(relation, SnapshotNow, 1, entry);
- tuple = heap_getnext(scan, ForwardScanDirection);
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(tblId));
+ scan = systable_beginscan(relation, TablespaceOidIndexId, true,
+ SnapshotNow, 1, entry);
+ tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("tablespace \"%s\" does not exist", spcname)));
+ elog(ERROR, "cache lookup failed for tablespace %u", tblId);
+
pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
/*
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);
+ NameStr(pg_tablespace_tuple->spcname));
}
/*
* GRANT case.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
- if (stmt->is_grant)
+ if (is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
*/
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,
+ new_acl = merge_acl_with_grant(old_acl, is_grant,
+ grant_option, behavior,
+ grantees, this_privileges,
grantorId, ownerId);
nnewmembers = aclmembers(new_acl, &newmembers);
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);
+ newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(relation, newtuple);
/* Update the shared dependency ACL info */
- updateAclDependencies(TableSpaceRelationId, HeapTupleGetOid(tuple),
- ownerId, stmt->is_grant,
+ updateAclDependencies(TableSpaceRelationId, tblId,
+ ownerId, is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
- pfree(new_acl);
+ systable_endscan(scan);
- heap_endscan(scan);
- heap_close(relation, RowExclusiveLock);
+ pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
+
+ heap_close(relation, RowExclusiveLock);
}
AclMode result;
Relation pg_database;
ScanKeyData entry[1];
- HeapScanDesc scan;
+ SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
- scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
- tuple = heap_getnext(scan, ForwardScanDirection);
+ scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
+ SnapshotNow, 1, entry);
+ tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
- heap_endscan(scan);
+ systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
- HeapScanDesc scan;
+ SysScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
- scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
- tuple = heap_getnext(scan, ForwardScanDirection);
+ scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
+ SnapshotNow, 1, entry);
+ tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
- heap_endscan(scan);
+ systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
{
Relation pg_tablespace;
ScanKeyData entry[1];
- HeapScanDesc scan;
+ SysScanDesc scan;
HeapTuple spctuple;
Oid spcowner;
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
- scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
+ scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
+ SnapshotNow, 1, entry);
- spctuple = heap_getnext(scan, ForwardScanDirection);
+ spctuple = systable_getnext(scan);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
- heap_endscan(scan);
+ systable_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return has_privs_of_role(roleid, spcowner);
{
Relation pg_database;
ScanKeyData entry[1];
- HeapScanDesc scan;
+ SysScanDesc scan;
HeapTuple dbtuple;
Oid dba;
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
- scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
+ scan = systable_beginscan(pg_database, DatabaseOidIndexId, true,
+ SnapshotNow, 1, entry);
- dbtuple = heap_getnext(scan, ForwardScanDirection);
+ dbtuple = systable_getnext(scan);
if (!HeapTupleIsValid(dbtuple))
ereport(ERROR,
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
- heap_endscan(scan);
+ systable_endscan(scan);
heap_close(pg_database, AccessShareLock);
return has_privs_of_role(roleid, dba);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.15 2005/10/15 02:49:14 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.16 2005/11/21 12:49:30 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
return count;
}
+/*
+ * 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
*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.3 2005/10/15 02:49:14 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.4 2005/11/21 12:49:30 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#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"
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);
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.24 2005/11/19 17:39:44 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.25 2005/11/21 12:49:30 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
+ Oid newOwnerId);
/*
* CREATE CONVERSION
}
/*
- * Change conversion owner
+ * Change conversion owner, by name
*/
void
AlterConversionOwner(List *name, Oid newOwnerId)
{
Oid conversionOid;
- HeapTuple tup;
Relation rel;
- Form_pg_conversion convForm;
- AclResult aclresult;
rel = heap_open(ConversionRelationId, RowExclusiveLock);
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);
*/
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,
- NameListToString(name));
+ NameStr(convForm->conname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
newOwnerId);
}
- heap_close(rel, NoLock);
heap_freetuple(tup);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.69 2005/10/15 02:49:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.70 2005/11/21 12:49:31 alvherre Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
#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
}
/*
- * Change function owner
+ * Change function owner by name and args
*/
void
AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
{
+ Relation rel;
Oid procOid;
HeapTuple tup;
- Form_pg_proc procForm;
- Relation rel;
- AclResult aclresult;
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
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)
+ 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.
/* Otherwise, must be owner of the existing object */
if (!pg_proc_ownercheck(procOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
- NameListToString(name));
+ NameStr(procForm->proname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
}
- newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
+ newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val,
+ repl_null, repl_repl);
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
}
ReleaseSysCache(tup);
- heap_close(rel, NoLock);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.38 2005/10/15 02:49:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.39 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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);
/*
}
/*
- * Change opclass owner
+ * 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 opcOid;
Oid amOid;
- Oid namespaceOid;
- char *schemaname;
- char *opcname;
- HeapTuple tup;
Relation rel;
- AclResult aclresult;
- Form_pg_opclass opcForm;
+ HeapTuple tup;
+ char *opcname;
+ char *schemaname;
amOid = GetSysCacheOid(AMNAME,
CStringGetDatum(access_method),
if (schemaname)
{
+ Oid namespaceOid;
+
namespaceOid = LookupExplicitNamespace(schemaname);
tup = SearchSysCacheCopy(CLAAMNAMENSP,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator class \"%s\" does not exist for access method \"%s\"",
opcname, access_method)));
-
- opcOid = HeapTupleGetOid(tup);
}
else
{
+ Oid opcOid;
+
opcOid = OpclassnameGetOpcid(amOid, opcname);
if (!OidIsValid(opcOid))
ereport(ERROR,
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;
}
+
+ 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.
/* 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));
+ NameStr(opcForm->opcname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
- changeDependencyOnOwner(OperatorClassRelationId, opcOid, newOwnerId);
+ changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup),
+ newOwnerId);
}
-
- heap_close(rel, NoLock);
- heap_freetuple(tup);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.26 2005/10/15 02:49:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.27 2005/11/21 12:49:31 alvherre Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
#include "utils/syscache.h"
+static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
+
/*
* DefineOperator
* this function extracts all the information from the
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
*/
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);
+ 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);
/* Otherwise, must be owner of the existing object */
if (!pg_oper_ownercheck(operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
- NameListToString(name));
+ NameStr(oprForm->oprname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);
}
- heap_close(rel, NoLock);
heap_freetuple(tup);
-
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.36 2005/11/19 17:39:44 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.37 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
+static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
+
/*
* CREATE SCHEMA
*/
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
*/
{
HeapTuple tup;
Relation rel;
- Form_pg_namespace nspForm;
rel = heap_open(NamespaceRelationId, RowExclusiveLock);
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);
/*
/* Otherwise, must be owner of the existing object */
if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
- name);
+ NameStr(nspForm->nspname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
newOwnerId);
}
- ReleaseSysCache(tup);
- heap_close(rel, NoLock);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.174 2005/10/15 02:49:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.175 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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);
* checks (this is necessary not just an optimization, else we'd fail to
* handle toast tables properly).
*/
-static void
+void
ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
{
Relation target_rel;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.83 2005/11/19 17:39:44 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.84 2005/11/21 12:49:31 alvherre Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
* 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.
+ * table's rowtype, and to implement REASSIGN OWNED BY. It assumes the
+ * caller has done all needed checks.
*/
void
AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.164 2005/11/04 17:25:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.165 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
auth_file_update_needed();
}
+/*
+ * 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
*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.318 2005/11/20 23:24:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.319 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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
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);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.255 2005/11/20 23:24:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.256 2005/11/21 12:49:31 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalDropOwnedStmt(DropOwnedStmt *a, DropOwnedStmt *b)
+{
+ COMPARE_NODE_FIELD(roles);
+ COMPARE_SCALAR_FIELD(behavior);
-/*
- * stuff from parsenodes.h
- */
+ 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)
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);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.513 2005/11/19 17:39:44 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.514 2005/11/21 12:49:31 alvherre Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
VariableResetStmt VariableSetStmt VariableShowStmt
ViewStmt CheckPointStmt CreateConversionStmt
DeallocateStmt PrepareStmt ExecuteStmt
+ DropOwnedStmt ReassignOwnedStmt
%type <node> select_no_parens select_with_parens select_clause
simple_select
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
+ ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER
PARTIAL PASSWORD PLACING POSITION
PRECISION PRESERVE PREPARE PREPARED PRIMARY
QUOTE
- READ REAL RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
+ READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT
ROLE ROLLBACK ROW ROWS RULE
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
+ | DropOwnedStmt
| DropPLangStmt
| DropRuleStmt
| DropStmt
| LockStmt
| NotifyStmt
| PrepareStmt
+ | ReassignOwnedStmt
| ReindexStmt
| RemoveAggrStmt
| RemoveFuncStmt
}
;
+/*****************************************************************************
+ *
+ * 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;
+ }
+ ;
/*****************************************************************************
*
| OIDS
| OPERATOR
| OPTION
+ | OWNED
| OWNER
| PARTIAL
| PASSWORD
| PROCEDURE
| QUOTE
| READ
+ | REASSIGN
| RECHECK
| REINDEX
| RELATIVE_P
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.167 2005/11/19 17:39:44 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.168 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
{"outer", OUTER_P},
{"overlaps", OVERLAPS},
{"overlay", OVERLAY},
+ {"owned", OWNED},
{"owner", OWNER},
{"partial", PARTIAL},
{"password", PASSWORD},
{"quote", QUOTE},
{"read", READ},
{"real", REAL},
+ {"reassign", REASSIGN},
{"recheck", RECHECK},
{"references", REFERENCES},
{"reindex", REINDEX},
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.246 2005/11/19 17:39:45 adunstan Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.247 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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")));
break;
/*
- * ******************************** object creation / destruction ********************************
- *
+ * **************** object creation / destruction ******************
*/
case T_DefineStmt:
{
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;
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;
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.17 2005/10/15 02:49:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.18 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
Oid refClassId, Oid oldRefObjectId,
Oid newRefObjectId);
+extern bool objectIsInternalDependency(Oid classId, Oid objectId);
+
/* in pg_shdepend.c */
extern void recordSharedDependencyOn(ObjectAddress *depender,
extern void dropDatabaseDependencies(Oid databaseId);
+extern void shdepDropOwned(List *relids, DropBehavior behavior);
+
+extern void shdepReassignOwned(List *relids, Oid newrole);
+
#endif /* DEPENDENCY_H */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.11 2005/11/19 17:39:45 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.12 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
DropBehavior behavior, bool missing_ok);
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 */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.68 2005/10/15 02:49:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.69 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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);
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);
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 */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.11 2005/11/19 17:39:45 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.12 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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 */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.24 2005/10/15 02:49:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.25 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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);
* Commands for manipulating roles (formerly called users).
*
*
- * $PostgreSQL: pgsql/src/include/commands/user.h,v 1.27 2005/06/28 05:09:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/user.h,v 1.28 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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 */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.176 2005/10/15 02:49:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.177 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
T_DropTableSpaceStmt,
T_AlterObjectSchemaStmt,
T_AlterOwnerStmt,
+ T_DropOwnedStmt,
+ T_ReassignOwnedStmt,
T_A_Expr = 800,
T_ColumnRef,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.293 2005/11/19 17:39:45 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.294 2005/11/21 12:49:32 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
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 */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.88 2005/11/18 02:38:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.89 2005/11/21 12:49:33 alvherre Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
* 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);
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;
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;