]> granicus.if.org Git - postgresql/commitdiff
Implement DROP OWNED and REASSIGN OWNED. These new commands facilitate the
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 21 Nov 2005 12:49:33 +0000 (12:49 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 21 Nov 2005 12:49:33 +0000 (12:49 +0000)
process of dropping roles by dropping objects owned by them and privileges
granted to them, or giving the owned objects to someone else, through the
use of the data stored in the new pg_shdepend catalog.

Some refactoring of the GRANT/REVOKE code was needed, as well as ALTER OWNER
code.  Further cleanup of code duplication in the GRANT code seems necessary.

Implemented by me after an idea from Tom Lane, who also provided various kind
of implementation advice.

Regression tests pass.  Some tests for the new functionality are also added,
as well as rudimentary documentation.

31 files changed:
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/drop_owned.sgml [new file with mode: 0644]
doc/src/sgml/ref/reassign_owned.sgml [new file with mode: 0644]
doc/src/sgml/reference.sgml
src/backend/catalog/aclchk.c
src/backend/catalog/pg_depend.c
src/backend/catalog/pg_shdepend.c
src/backend/commands/conversioncmds.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/schemacmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/commands/user.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/tcop/utility.c
src/include/catalog/dependency.h
src/include/commands/conversioncmds.h
src/include/commands/defrem.h
src/include/commands/schemacmds.h
src/include/commands/tablecmds.h
src/include/commands/user.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/utils/acl.h
src/test/regress/expected/dependency.out
src/test/regress/sql/dependency.sql

index c08b09b67d4b13404d8d26543f13fb5b094d6563..07dd0b0ee7453e8b6963480d2fed100450e4ff26 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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.
 -->
@@ -70,6 +70,7 @@ 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">
@@ -93,6 +94,7 @@ Complete list of usable sgml source files in this directory.
 <!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">
diff --git a/doc/src/sgml/ref/drop_owned.sgml b/doc/src/sgml/ref/drop_owned.sgml
new file mode 100644 (file)
index 0000000..dc8b01f
--- /dev/null
@@ -0,0 +1,99 @@
+<!--
+$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:
+-->
diff --git a/doc/src/sgml/ref/reassign_owned.sgml b/doc/src/sgml/ref/reassign_owned.sgml
new file mode 100644 (file)
index 0000000..a54e4c8
--- /dev/null
@@ -0,0 +1,89 @@
+<!--
+$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:
+-->
index 0191ec8b3c31b1b7c2f66532722b0c7c51d10904..f320a132d04b9789f6dbcb33fa6e0a709c728c39 100644 (file)
@@ -1,5 +1,5 @@
 <!-- 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
 -->
@@ -102,6 +102,7 @@ PostgreSQL Reference Manual
    &dropLanguage;
    &dropOperator;
    &dropOperatorClass;
+   &dropOwned;
    &dropRole;
    &dropRule;
    &dropSchema;
@@ -125,6 +126,7 @@ PostgreSQL Reference Manual
    &notify;
    &prepare;
    &prepareTransaction;
+   &reassignOwned;
    &reindex;
    &releaseSavepoint;
    &reset;
index 15a197af81b123d9725ee1f802634171fe52d768..b0bc8e28eaf790345f3a6b9a34da4eb5c07afbfb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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.
@@ -17,6 +17,7 @@
  */
 #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);
@@ -96,15 +110,10 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
 
        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.
@@ -151,71 +160,307 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
 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;
@@ -223,6 +468,7 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                Acl                *new_acl;
                Oid                     grantorId;
                Oid                     ownerId;
+               HeapTuple       tuple;
                HeapTuple       newtuple;
                Datum           values[Natts_pg_class];
                char            nulls[Natts_pg_class];
@@ -232,9 +478,6 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                Oid                *oldmembers;
                Oid                *newmembers;
 
-               /* open pg_class */
-               relation = heap_open(RelationRelationId, RowExclusiveLock);
-               relOid = RangeVarGetRelid(relvar, false);
                tuple = SearchSysCache(RELOID,
                                                           ObjectIdGetDatum(relOid),
                                                           0, 0, 0);
@@ -247,15 +490,14 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                        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.
@@ -285,7 +527,7 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                                                                 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));
                }
 
                /*
@@ -297,7 +539,7 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -328,9 +570,9 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
                 */
                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);
@@ -352,7 +594,7 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
 
                /* Update the shared dependency ACL info */
                updateAclDependencies(RelationRelationId, relOid,
-                                                         ownerId, stmt->is_grant,
+                                                         ownerId, is_grant,
                                                          noldmembers, oldmembers,
                                                          nnewmembers, newmembers);
 
@@ -360,50 +602,29 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
 
                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;
@@ -421,18 +642,23 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
                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);
 
                /*
@@ -476,7 +702,7 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -507,9 +733,9 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
                 */
                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);
@@ -522,7 +748,8 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
                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);
 
@@ -531,57 +758,37 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
 
                /* 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;
@@ -591,6 +798,7 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                Acl                *new_acl;
                Oid                     grantorId;
                Oid                     ownerId;
+               HeapTuple       tuple;
                HeapTuple       newtuple;
                Datum           values[Natts_pg_proc];
                char            nulls[Natts_pg_proc];
@@ -600,14 +808,12 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                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);
 
                /*
@@ -634,7 +840,7 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                 */
                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)
@@ -651,7 +857,7 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -682,9 +888,9 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                 */
                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);
@@ -697,7 +903,8 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                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);
 
@@ -705,8 +912,8 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
                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);
 
@@ -714,48 +921,29 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
 
                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;
@@ -765,6 +953,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
                Acl                *new_acl;
                Oid                     grantorId;
                Oid                     ownerId;
+               HeapTuple       tuple;
                HeapTuple       newtuple;
                Datum           values[Natts_pg_language];
                char            nulls[Natts_pg_language];
@@ -774,21 +963,20 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
                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,
@@ -834,7 +1022,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -865,9 +1053,9 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
                 */
                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);
@@ -880,7 +1068,8 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
                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);
 
@@ -889,7 +1078,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
 
                /* Update the shared dependency ACL info */
                updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
-                                                         ownerId, stmt->is_grant,
+                                                         ownerId, is_grant,
                                                          noldmembers, oldmembers,
                                                          nnewmembers, newmembers);
 
@@ -897,48 +1086,29 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
 
                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;
@@ -948,6 +1118,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                Acl                *new_acl;
                Oid                     grantorId;
                Oid                     ownerId;
+               HeapTuple       tuple;
                HeapTuple       newtuple;
                Datum           values[Natts_pg_namespace];
                char            nulls[Natts_pg_namespace];
@@ -957,14 +1128,12 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                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);
 
                /*
@@ -997,7 +1166,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                                                                         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));
                }
 
                /*
@@ -1009,7 +1178,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -1040,9 +1209,9 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                 */
                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);
@@ -1055,7 +1224,8 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
                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);
 
@@ -1064,7 +1234,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
 
                /* Update the shared dependency ACL info */
                updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
-                                                         ownerId, stmt->is_grant,
+                                                         ownerId, is_grant,
                                                          noldmembers, oldmembers,
                                                          nnewmembers, newmembers);
 
@@ -1072,50 +1242,29 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
 
                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;
@@ -1133,18 +1282,21 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                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);
 
                /*
@@ -1176,7 +1328,7 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                                                                          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));
                }
 
                /*
@@ -1188,7 +1340,7 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                 * GRANT case.)
                 */
                this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-               if (stmt->is_grant)
+               if (is_grant)
                {
                        if (this_privileges == 0)
                                ereport(WARNING,
@@ -1219,9 +1371,9 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                 */
                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);
@@ -1234,7 +1386,8 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                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);
 
@@ -1242,19 +1395,20 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
                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);
 }
 
 
@@ -1537,7 +1691,7 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
        AclMode         result;
        Relation        pg_database;
        ScanKeyData entry[1];
-       HeapScanDesc scan;
+       SysScanDesc     scan;
        HeapTuple       tuple;
        Datum           aclDatum;
        bool            isNull;
@@ -1558,8 +1712,9 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
                                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),
@@ -1588,7 +1743,7 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
                pfree(acl);
 
-       heap_endscan(scan);
+       systable_endscan(scan);
        heap_close(pg_database, AccessShareLock);
 
        return result;
@@ -1801,7 +1956,7 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
        AclMode         result;
        Relation        pg_tablespace;
        ScanKeyData entry[1];
-       HeapScanDesc scan;
+       SysScanDesc     scan;
        HeapTuple       tuple;
        Datum           aclDatum;
        bool            isNull;
@@ -1829,8 +1984,9 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
                                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),
@@ -1859,7 +2015,7 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
                pfree(acl);
 
-       heap_endscan(scan);
+       systable_endscan(scan);
        heap_close(pg_tablespace, AccessShareLock);
 
        return result;
@@ -2091,7 +2247,7 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
 {
        Relation        pg_tablespace;
        ScanKeyData entry[1];
-       HeapScanDesc scan;
+       SysScanDesc     scan;
        HeapTuple       spctuple;
        Oid                     spcowner;
 
@@ -2105,9 +2261,10 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
                                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,
@@ -2116,7 +2273,7 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
 
        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);
@@ -2159,7 +2316,7 @@ pg_database_ownercheck(Oid db_oid, Oid roleid)
 {
        Relation        pg_database;
        ScanKeyData entry[1];
-       HeapScanDesc scan;
+       SysScanDesc     scan;
        HeapTuple       dbtuple;
        Oid                     dba;
 
@@ -2173,9 +2330,10 @@ pg_database_ownercheck(Oid db_oid, Oid roleid)
                                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,
@@ -2184,7 +2342,7 @@ pg_database_ownercheck(Oid db_oid, Oid roleid)
 
        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);
index c8f9e53212d1be5498ac7b7f99c83e4b7508ec54..848183dae5dc558448987d7a80ba86ad703f2d6d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -162,6 +162,58 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
        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
  *
index 4cce7ba13cff36c37f8367b2c3fdef31a41a380a..6bd69cdef6c1b85ba98c3cb69d4991b65e5fe29f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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"
@@ -1042,3 +1055,251 @@ isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
 
        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 97abc9fc77410e29b5dc26de479dee0ddc37efc1..42bb0853a10b9e13c671333300426dac291e1f09 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,6 +30,8 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
+                                                                        Oid newOwnerId);
 
 /*
  * CREATE CONVERSION
@@ -185,16 +187,13 @@ RenameConversion(List *name, const char *newname)
 }
 
 /*
- * 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);
 
@@ -205,6 +204,40 @@ AlterConversionOwner(List *name, Oid newOwnerId)
                                 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);
@@ -219,13 +252,15 @@ AlterConversionOwner(List *name, Oid newOwnerId)
         */
        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);
@@ -253,6 +288,5 @@ AlterConversionOwner(List *name, Oid newOwnerId)
                                                                newOwnerId);
        }
 
-       heap_close(rel, NoLock);
        heap_freetuple(tup);
 }
index f4d6164775ee48e636aa78c819b9755c1a16a96d..77f892fe501f8e77e3df70cdd0e45a287ebdfb67 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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
@@ -55,6 +55,7 @@
 #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,16 +854,14 @@ RenameFunction(List *name, List *argtypes, const char *newname)
 }
 
 /*
- * 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);
 
@@ -873,15 +872,53 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
                                                 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.
@@ -902,7 +939,7 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
                        /* 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);
@@ -937,7 +974,8 @@ AlterFunctionOwner(List *name, List *argtypes, Oid 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);
@@ -949,7 +987,6 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
        }
 
        ReleaseSysCache(tup);
-       heap_close(rel, NoLock);
 }
 
 /*
index ea8afcfccbf8bbf249609169b5bc176e85a7b9da..10745032de2f3d460014dbce74bcca44b82ed4b0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,8 @@ static Oid    assignProcSubtype(Oid amoid, Oid typeoid, Oid procOid);
 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,20 +881,39 @@ RenameOpClass(List *name, const char *access_method, const char *newname)
 }
 
 /*
- * 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),
@@ -912,6 +933,8 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
 
        if (schemaname)
        {
+               Oid             namespaceOid;
+
                namespaceOid = LookupExplicitNamespace(schemaname);
 
                tup = SearchSysCacheCopy(CLAAMNAMENSP,
@@ -924,11 +947,11 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
                                        (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,
@@ -941,10 +964,32 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
                                                                 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.
@@ -957,7 +1002,7 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
                        /* 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);
@@ -980,9 +1025,7 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
                CatalogUpdateIndexes(rel, tup);
 
                /* Update owner dependency reference */
-               changeDependencyOnOwner(OperatorClassRelationId, opcOid, newOwnerId);
+               changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup),
+                                                               newOwnerId);
        }
-
-       heap_close(rel, NoLock);
-       heap_freetuple(tup);
 }
index 07877962e3f152bdcc9f54e62beae8b74ddc5bdc..bcc2abe5fb718898f7103eca42594f44221d17e3 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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
@@ -48,6 +48,8 @@
 #include "utils/syscache.h"
 
 
+static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
+
 /*
  * DefineOperator
  *             this function extracts all the information from the
@@ -260,6 +262,18 @@ RemoveOperatorById(Oid operOid)
        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,16 +282,27 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
                                   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);
@@ -298,7 +323,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
                        /* 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);
@@ -325,7 +350,5 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
                changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);
        }
 
-       heap_close(rel, NoLock);
        heap_freetuple(tup);
-
 }
index caa336d2c455395f12b4a830e96e6203caba0e56..7a7b930ce055c0496f5622a8d195fd3798c41709 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,8 @@
 #include "utils/syscache.h"
 
 
+static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
+
 /*
  * CREATE SCHEMA
  */
@@ -277,6 +279,28 @@ RenameSchema(const char *oldname, const char *newname)
        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
  */
@@ -285,7 +309,6 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
 {
        HeapTuple       tup;
        Relation        rel;
-       Form_pg_namespace nspForm;
 
        rel = heap_open(NamespaceRelationId, RowExclusiveLock);
 
@@ -296,6 +319,22 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
                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);
 
        /*
@@ -316,7 +355,7 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
                /* 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);
@@ -369,6 +408,4 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
                                                                newOwnerId);
        }
 
-       ReleaseSysCache(tup);
-       heap_close(rel, NoLock);
 }
index abec1a835d1b6352846dcc08dd7fcf1cc3041f0e..09161e0d4b914567413b0e34a668ccafb3b7865b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -236,7 +236,6 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                          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);
@@ -5264,7 +5263,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
  * 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;
index 475c251b2fc17100e8572f4ce1ebe385aacccf80..30044f10bf129b8c4160ddf68ab3d466d584fc0c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -2122,7 +2122,8 @@ AlterTypeOwner(List *names, Oid newOwnerId)
  * 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)
index 91befbc6aba3966277b216d59f406876c37780de..9ac3c8a97ef5a6805a1ea11c7ceac7c3ccb62514 100644 (file)
@@ -6,7 +6,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1118,6 +1118,67 @@ GrantRole(GrantRoleStmt *stmt)
        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
  *
index 1b3c6076fc049fb4388d5e5ea1e55483693ff36e..bfce72b4057bde211d0786a8c3ef15ed39fd6141 100644 (file)
@@ -15,7 +15,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -2595,6 +2595,27 @@ _copyDeallocateStmt(DeallocateStmt *from)
        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
@@ -3146,6 +3167,12 @@ copyObject(void *from)
                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 bc9c8f3f2a5ebf65d7bc0541d2a0b91f20256980..fa27e5871b986a06ee9cd74cd6175d4db4c49bde 100644 (file)
@@ -18,7 +18,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1469,10 +1469,23 @@ _equalDeallocateStmt(DeallocateStmt *a, DeallocateStmt *b)
        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)
@@ -2188,6 +2201,13 @@ equal(void *a, void *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);
index c91100abe4e0cf0ea30d996dbbff9ed47bef9902..15b079ca6ff417aa2c0eb734ef272b8a9ebb229b 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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
@@ -153,6 +153,7 @@ static void doNegateFloat(Value *v);
                VariableResetStmt VariableSetStmt VariableShowStmt
                ViewStmt CheckPointStmt CreateConversionStmt
                DeallocateStmt PrepareStmt ExecuteStmt
+               DropOwnedStmt ReassignOwnedStmt
 
 %type <node>   select_no_parens select_with_parens select_clause
                                simple_select
@@ -382,7 +383,7 @@ static void doNegateFloat(Value *v);
        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
@@ -390,7 +391,7 @@ static void doNegateFloat(Value *v);
 
        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
 
@@ -533,6 +534,7 @@ stmt :
                        | DropCastStmt
                        | DropGroupStmt
                        | DropOpClassStmt
+                       | DropOwnedStmt
                        | DropPLangStmt
                        | DropRuleStmt
                        | DropStmt
@@ -553,6 +555,7 @@ stmt :
                        | LockStmt
                        | NotifyStmt
                        | PrepareStmt
+                       | ReassignOwnedStmt
                        | ReindexStmt
                        | RemoveAggrStmt
                        | RemoveFuncStmt
@@ -2813,6 +2816,33 @@ DropOpClassStmt:
                                }
                ;
 
+/*****************************************************************************
+ *
+ *             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;
+                               }
+               ;
 
 /*****************************************************************************
  *
@@ -8222,6 +8252,7 @@ unreserved_keyword:
                        | OIDS
                        | OPERATOR
                        | OPTION
+                       | OWNED
                        | OWNER
                        | PARTIAL
                        | PASSWORD
@@ -8234,6 +8265,7 @@ unreserved_keyword:
                        | PROCEDURE
                        | QUOTE
                        | READ
+                       | REASSIGN
                        | RECHECK
                        | REINDEX
                        | RELATIVE_P
index 797ea610db5ac22f700eae06ec681e4e53e67f87..639c260b69ba894127b1bf6c24ac2fce4760c69a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -252,6 +252,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"outer", OUTER_P},
        {"overlaps", OVERLAPS},
        {"overlay", OVERLAY},
+       {"owned", OWNED},
        {"owner", OWNER},
        {"partial", PARTIAL},
        {"password", PASSWORD},
@@ -269,6 +270,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"quote", QUOTE},
        {"read", READ},
        {"real", REAL},
+       {"reassign", REASSIGN},
        {"recheck", RECHECK},
        {"references", REFERENCES},
        {"reindex", REINDEX},
index 75458bfce352f331b0336ef3781d9508ba2644aa..a17021eb2916550000bf24d7112652eb31b909d5 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -347,6 +347,8 @@ check_xact_readonly(Node *parsetree)
                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")));
@@ -725,8 +727,7 @@ ProcessUtility(Node *parsetree,
                        break;
 
                        /*
-                        * ******************************** object creation / destruction ********************************
-                        *
+                        * **************** object creation / destruction ******************
                         */
                case T_DefineStmt:
                        {
@@ -1019,6 +1020,14 @@ ProcessUtility(Node *parsetree,
                        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;
@@ -1677,6 +1686,14 @@ CreateCommandTag(Node *parsetree)
                        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 5c5e87c746e952c511e7ceae2c1ba197d8c1b376..c91406390b015f96fecdc1a551856e967320d6ce 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -177,6 +177,8 @@ extern long changeDependencyFor(Oid classId, Oid objectId,
                                        Oid refClassId, Oid oldRefObjectId,
                                        Oid newRefObjectId);
 
+extern bool objectIsInternalDependency(Oid classId, Oid objectId);
+
 /* in pg_shdepend.c */
 
 extern void recordSharedDependencyOn(ObjectAddress *depender,
@@ -201,4 +203,8 @@ extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId);
 
 extern void dropDatabaseDependencies(Oid databaseId);
 
+extern void shdepDropOwned(List *relids, DropBehavior behavior);
+
+extern void shdepReassignOwned(List *relids, Oid newrole);
+
 #endif   /* DEPENDENCY_H */
index f484ceaff2cf112dd1f212be88c973941486bf0b..05d30a31cba3ebe3bbccc31d0b3b8b8b7cdce911 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,5 +22,6 @@ extern void DropConversionCommand(List *conversion_name,
                                                                  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 */
index ad7c6a178a02c8d8650a0b28d733b665f581567d..39603cf31f27bd7de9e9218da54b9f36bb3ae3d0 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,7 @@ extern void SetFunctionReturnType(Oid funcOid, Oid newRetType);
 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,6 +65,7 @@ extern void RemoveOperator(RemoveOperStmt *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);
@@ -77,6 +79,7 @@ extern void RemoveOpClass(RemoveOpClassStmt *stmt);
 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 f47baf6ef3b71a65450ad48d1e59092d14c2167c..6611364bf75076313a11d1be0977af5491f8f943 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,5 +24,6 @@ extern void RemoveSchemaById(Oid schemaOid);
 
 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 077416484486489358765bb59b91bd2f13a03c7e..b6e30f6f699b27f9268d3b235cbac9bf379d3bc4 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,8 @@ extern void RemoveRelation(const RangeVar *relation, DropBehavior behavior);
 
 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 ab2829a266bba88730e1ff4892103fd6784ec878..a8fba2f874d349468bf155484cdb1186b9354ab4 100644 (file)
@@ -4,7 +4,7 @@
  *       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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,5 +20,7 @@ extern void AlterRoleSet(AlterRoleSetStmt *stmt);
 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 327e4301ff9549be2b5fb96f68b5e2b4e76282e2..919753ea92fc9b269dca3934c12fb6ebd16aa814 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -286,6 +286,8 @@ typedef enum NodeTag
        T_DropTableSpaceStmt,
        T_AlterObjectSchemaStmt,
        T_AlterOwnerStmt,
+       T_DropOwnedStmt,
+       T_ReassignOwnedStmt,
 
        T_A_Expr = 800,
        T_ColumnRef,
index 8baed3e4491e5d895076f487e9192a429df4bf22..a482abfb351e9c5d64605a34a9944e568e63117c 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1875,4 +1875,24 @@ typedef struct DeallocateStmt
        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 8699913eb95cf1a1e7be656e3ccd42846c36d4df..7b2122b9a9f1f47923265f1ac1a02f72579e99ee 100644 (file)
@@ -7,7 +7,7 @@
  * 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
@@ -221,6 +221,9 @@ extern Datum hash_aclitem(PG_FUNCTION_ARGS);
  * 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 2c31e581bfe84353c63dc1dbf2ec2d0269992f06..4781b5f9f29841abe3b82f175ffb75244dce8d61 100644 (file)
@@ -38,6 +38,76 @@ DROP USER regression_user2;
 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 3e4a232ea716654908b9e0d9eb1f50c250c92644..c1b189f527894d77e32631710ec9b9d01dc90a75 100644 (file)
@@ -39,6 +39,55 @@ DROP USER regression_user2;
 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;