Refactor some bits in aclchk.c in order to reduce code duplication.
authorAlvaro Herrera
Thu, 1 Dec 2005 02:03:01 +0000 (02:03 +0000)
committerAlvaro Herrera
Thu, 1 Dec 2005 02:03:01 +0000 (02:03 +0000)
src/backend/catalog/aclchk.c
src/backend/catalog/pg_shdepend.c
src/include/utils/acl.h

index 690a24e3f39407d3937b0ca877d2ab937bd3aad4..643d31c19954e428ef0c32797e4fdeafc5e89ffe 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.122 2005/11/22 18:17:07 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.123 2005/12/01 02:03:00 alvherre Exp $
  *
  * NOTES
  *   See acl.h.
 #include "utils/syscache.h"
 
 
-static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior);
-static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior);
-static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior);
-static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior);
-static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
-                   AclMode privileges, List *grantees, bool grant_option,
-                   DropBehavior behavior);
-static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
-                    AclMode privileges, List *grantees, bool grant_option,
-                    DropBehavior behavior);
-static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
+static void ExecGrant_Relation(InternalGrant *grantStmt);
+static void ExecGrant_Database(InternalGrant *grantStmt);
+static void ExecGrant_Function(InternalGrant *grantStmt);
+static void ExecGrant_Language(InternalGrant *grantStmt);
+static void ExecGrant_Namespace(InternalGrant *grantStmt);
+static void ExecGrant_Tablespace(InternalGrant *grantStmt);
 
+static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
 static AclMode string_to_privilege(const char *privname);
 static const char *privilege_to_string(AclMode privilege);
+static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
+                                       bool all_privs, AclMode privileges,
+                                       Oid objectId, Oid grantorId,
+                                       AclObjectKind objkind, char *objname);
+static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
+          AclMode mask, AclMaskHow how);
 
 
 #ifdef ACLDEBUG
@@ -153,6 +147,91 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
    return new_acl;
 }
 
+/*
+ * Restrict the privileges to what we can actually grant, and emit
+ * the standards-mandated warning and error messages.
+ */
+static AclMode
+restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
+                        AclMode privileges, Oid objectId, Oid grantorId,
+                        AclObjectKind objkind, char *objname)
+{
+   AclMode this_privileges;
+   AclMode whole_mask;
+
+   switch (objkind)
+   {
+       case ACL_KIND_CLASS:
+           whole_mask = ACL_ALL_RIGHTS_RELATION;
+           break;
+       case ACL_KIND_DATABASE:
+           whole_mask = ACL_ALL_RIGHTS_DATABASE;
+           break;
+       case ACL_KIND_PROC:
+           whole_mask = ACL_ALL_RIGHTS_FUNCTION;
+           break;
+       case ACL_KIND_LANGUAGE:
+           whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
+           break;
+       case ACL_KIND_NAMESPACE:
+           whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
+           break;
+       case ACL_KIND_TABLESPACE:
+           whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
+           break;
+       default:
+           elog(ERROR, "unrecognized object kind: %d", objkind);
+           /* not reached, but keep compiler quiet */
+           return ACL_NO_RIGHTS;
+   }
+
+   /*
+    * If we found no grant options, consider whether to issue a hard
+    * error.  Per spec, having any privilege at all on the object will
+    * get you by here.
+    */
+   if (avail_goptions == ACL_NO_RIGHTS)
+   {
+       if (pg_aclmask(objkind, objectId, grantorId,
+                      whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+                      ACLMASK_ANY) == ACL_NO_RIGHTS)
+           aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
+   }
+
+   /*
+    * Restrict the operation to what we can actually grant or revoke, and
+    * issue a warning if appropriate.  (For REVOKE this isn't quite what
+    * the spec says to do: the spec seems to want a warning only if no
+    * privilege bits actually change in the ACL. In practice that
+    * behavior seems much too noisy, as well as inconsistent with the
+    * GRANT case.)
+    */
+   this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+   if (is_grant)
+   {
+       if (this_privileges == 0)
+           ereport(WARNING,
+                   (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+                    errmsg("no privileges were granted")));
+       else if (!all_privs && this_privileges != privileges)
+           ereport(WARNING,
+                   (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+                    errmsg("not all privileges were granted")));
+   }
+   else
+   {
+       if (this_privileges == 0)
+           ereport(WARNING,
+                   (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+                    errmsg("no privileges could be revoked")));
+       else if (!all_privs && this_privileges != privileges)
+           ereport(WARNING,
+                   (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+                    errmsg("not all privileges could be revoked")));
+   }
+
+   return this_privileges;
+}
 
 /*
  * Called to execute the utility commands GRANT and REVOKE
@@ -160,13 +239,24 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
 void
 ExecuteGrantStmt(GrantStmt *stmt)
 {
-   List       *objects;
-   List       *grantees = NIL;
-   AclMode     privileges;
+   InternalGrant istmt;
    ListCell   *cell;
-   bool        all_privs;
-   AclMode     all_privileges = (AclMode) 0;
-   char       *errormsg = NULL;
+   char       *errormsg;
+   AclMode     all_privileges;
+
+   /*
+    * Turn the regular GrantStmt into the InternalGrant form.
+    */
+   istmt.is_grant = stmt->is_grant;
+   istmt.objtype = stmt->objtype;
+   istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
+   /* all_privs to be filled below */
+   /* privileges to be filled below */
+   istmt.grantees = NIL;
+   /* filled below */
+   istmt.grant_option = stmt->grant_option;
+   istmt.behavior = stmt->behavior;
+
 
    /*
     * Convert the PrivGrantee list into an Oid list.  Note that at this point
@@ -180,15 +270,15 @@ ExecuteGrantStmt(GrantStmt *stmt)
        PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
 
        if (grantee->rolname == NULL)
-           grantees = lappend_oid(grantees, ACL_ID_PUBLIC);
+           istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
        else
-           grantees = lappend_oid(grantees,
-                                  get_roleid_checked(grantee->rolname));
+           istmt.grantees =
+               lappend_oid(istmt.grantees,
+                           get_roleid_checked(grantee->rolname));
    }
 
    /*
-    * Convert stmt->privileges, a textual list, into an AclMode bitmask
-    * appropiate for the given object class.
+    * Convert stmt->privileges, a textual list, into an AclMode bitmask.
     */
    switch (stmt->objtype)
    {
@@ -217,19 +307,26 @@ ExecuteGrantStmt(GrantStmt *stmt)
            errormsg = _("invalid privilege type %s for tablespace");
            break;
        default:
+           /* keep compiler quiet */
+           all_privileges = ACL_NO_RIGHTS;
+           errormsg = NULL;
            elog(ERROR, "unrecognized GrantStmt.objtype: %d",
                 (int) stmt->objtype);
    }
 
    if (stmt->privileges == NIL)
    {
-       all_privs = true;
-       privileges = all_privileges;
+       istmt.all_privs = true;
+       /*
+        * will be turned into ACL_ALL_RIGHTS_* by the internal routines
+        * depending on the object type
+        */
+       istmt.privileges = ACL_NO_RIGHTS;
    }
    else
    {
-       all_privs = false;
-       privileges = ACL_NO_RIGHTS;
+       istmt.all_privs = false;
+       istmt.privileges = ACL_NO_RIGHTS;
        foreach(cell, stmt->privileges)
        {
            char       *privname = strVal(lfirst(cell));
@@ -241,61 +338,44 @@ ExecuteGrantStmt(GrantStmt *stmt)
                         errmsg(errormsg,
                                privilege_to_string(priv))));
 
-           privileges |= priv;
+           istmt.privileges |= priv;
        }
    }
 
-   /* Turn the list of object names into an Oid list */
-   objects = objectNamesToOids(stmt->objtype, stmt->objects);
-
-   ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
-                      privileges, grantees, stmt->grant_option,
-                      stmt->behavior);
+   ExecGrantStmt_oids(&istmt);
 }
 
 /*
  * 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.
+ * "Internal" entrypoint for granting and revoking privileges.
  */
 void
-ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
-                  bool all_privs, AclMode privileges, List *grantees,
-                  bool grant_option, DropBehavior behavior)
+ExecGrantStmt_oids(InternalGrant *istmt)
 {
-   switch (objtype)
+   switch (istmt->objtype)
    {
        case ACL_OBJECT_RELATION:
-           ExecGrant_Relation(is_grant, objects, all_privs, privileges,
-                              grantees, grant_option, behavior);
+           ExecGrant_Relation(istmt);
            break;
        case ACL_OBJECT_DATABASE:
-           ExecGrant_Database(is_grant, objects, all_privs, privileges,
-                              grantees, grant_option, behavior);
+           ExecGrant_Database(istmt);
            break;
        case ACL_OBJECT_FUNCTION:
-           ExecGrant_Function(is_grant, objects, all_privs, privileges,
-                              grantees, grant_option, behavior);
+           ExecGrant_Function(istmt);
            break;
        case ACL_OBJECT_LANGUAGE:
-           ExecGrant_Language(is_grant, objects, all_privs, privileges,
-                              grantees, grant_option, behavior);
+           ExecGrant_Language(istmt);
            break;
        case ACL_OBJECT_NAMESPACE:
-           ExecGrant_Namespace(is_grant, objects, all_privs,
-                               privileges, grantees, grant_option,
-                               behavior);
+           ExecGrant_Namespace(istmt);
            break;
        case ACL_OBJECT_TABLESPACE:
-           ExecGrant_Tablespace(is_grant, objects, all_privs,
-                                privileges, grantees, grant_option,
-                                behavior);
+           ExecGrant_Tablespace(istmt);
            break;
        default:
            elog(ERROR, "unrecognized GrantStmt.objtype: %d",
-                (int) objtype);
+                (int) istmt->objtype);
    }
 }
 
@@ -444,19 +524,17 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
 }
 
 static void
-ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior)
+ExecGrant_Relation(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_RELATION;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_RELATION;
 
    relation = heap_open(RelationRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
        Oid         relOid = lfirst_oid(cell);
        Datum       aclDatum;
@@ -512,56 +590,19 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_class_aclmask(relOid,
-                                grantorId,
-                                ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION),
-                                ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
-                              NameStr(pg_class_tuple->relname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
-        */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    relOid, grantorId, ACL_KIND_CLASS,
+                                    NameStr(pg_class_tuple->relname));
 
        /*
         * Generate new ACL.
@@ -571,9 +612,9 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -595,7 +636,7 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(RelationRelationId, relOid,
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -611,19 +652,17 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
 }
 
 static void
-ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior)
+ExecGrant_Database(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_DATABASE;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
 
    relation = heap_open(DatabaseRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
        Oid         datId = lfirst_oid(cell);
        Form_pg_database pg_database_tuple;
@@ -675,56 +714,19 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
-        */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_database_aclmask(HeapTupleGetOid(tuple),
-                                   grantorId,
-                                   ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
-                                   ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
-                              NameStr(pg_database_tuple->datname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    datId, grantorId, ACL_KIND_DATABASE,
+                                    NameStr(pg_database_tuple->datname));
 
        /*
         * Generate new ACL.
@@ -734,9 +736,9 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -759,7 +761,7 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -775,19 +777,17 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
 }
 
 static void
-ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior)
+ExecGrant_Function(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_FUNCTION;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
 
    relation = heap_open(ProcedureRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
        Oid         funcId = lfirst_oid(cell);
        Form_pg_proc pg_proc_tuple;
@@ -830,56 +830,19 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_proc_aclmask(funcId,
-                               grantorId,
-                               ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION),
-                               ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
-                              NameStr(pg_proc_tuple->proname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
-        */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    funcId, grantorId, ACL_KIND_PROC,
+                                    NameStr(pg_proc_tuple->proname));
 
        /*
         * Generate new ACL.
@@ -889,9 +852,9 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -914,7 +877,7 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(ProcedureRelationId, funcId,
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -930,21 +893,19 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
 }
 
 static void
-ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
-                  AclMode privileges, List *grantees, bool grant_option,
-                  DropBehavior behavior)
+ExecGrant_Language(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_LANGUAGE;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
 
    relation = heap_open(LanguageRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
-       Oid         langid = lfirst_oid(cell);
+       Oid         langId = lfirst_oid(cell);
        Form_pg_language pg_language_tuple;
        Datum       aclDatum;
        bool        isNull;
@@ -965,10 +926,10 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
        Oid        *newmembers;
 
        tuple = SearchSysCache(LANGOID,
-                              ObjectIdGetDatum(langid),
+                              ObjectIdGetDatum(langId),
                               0, 0, 0);
        if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for language %u", langid);
+           elog(ERROR, "cache lookup failed for language %u", langId);
 
        pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
 
@@ -995,56 +956,19 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_language_aclmask(HeapTupleGetOid(tuple),
-                                   grantorId,
-                                   ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
-                                   ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
-                              NameStr(pg_language_tuple->lanname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
-        */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    langId, grantorId, ACL_KIND_LANGUAGE,
+                                    NameStr(pg_language_tuple->lanname));
 
        /*
         * Generate new ACL.
@@ -1054,9 +978,9 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -1079,7 +1003,7 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -1095,19 +1019,17 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
 }
 
 static void
-ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
-                   AclMode privileges, List *grantees, bool grant_option,
-                   DropBehavior behavior)
+ExecGrant_Namespace(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_NAMESPACE;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
 
    relation = heap_open(NamespaceRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
        Oid         nspid = lfirst_oid(cell);
        Form_pg_namespace pg_namespace_tuple;
@@ -1151,56 +1073,19 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
-        */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_namespace_aclmask(HeapTupleGetOid(tuple),
-                                    grantorId,
-                                    ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE),
-                                    ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
-                              NameStr(pg_namespace_tuple->nspname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    nspid, grantorId, ACL_KIND_NAMESPACE,
+                                    NameStr(pg_namespace_tuple->nspname));
 
        /*
         * Generate new ACL.
@@ -1210,9 +1095,9 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -1235,7 +1120,7 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -1251,19 +1136,17 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
 }
 
 static void
-ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
-                    AclMode privileges, List *grantees, bool grant_option,
-                    DropBehavior behavior)
+ExecGrant_Tablespace(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
-   if (all_privs && privileges == ACL_NO_RIGHTS)
-       privileges = ACL_ALL_RIGHTS_TABLESPACE;
+   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+       istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
 
    relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
 
-   foreach(cell, objects)
+   foreach(cell, istmt->objects)
    {
        Oid         tblId = lfirst_oid(cell);
        Form_pg_tablespace pg_tablespace_tuple;
@@ -1313,56 +1196,19 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
            old_acl = DatumGetAclPCopy(aclDatum);
 
        /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), privileges,
+       select_best_grantor(GetUserId(), istmt->privileges,
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
        /*
-        * If we found no grant options, consider whether to issue a hard
-        * error.  Per spec, having any privilege at all on the object will
-        * get you by here.
+        * Restrict the privileges to what we can actually grant, and emit
+        * the standards-mandated warning and error messages.
         */
-       if (avail_goptions == ACL_NO_RIGHTS)
-       {
-           if (pg_tablespace_aclmask(HeapTupleGetOid(tuple),
-                                     grantorId,
-                                     ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE),
-                                     ACLMASK_ANY) == ACL_NO_RIGHTS)
-               aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
-                              NameStr(pg_tablespace_tuple->spcname));
-       }
-
-       /*
-        * Restrict the operation to what we can actually grant or revoke, and
-        * issue a warning if appropriate.  (For REVOKE this isn't quite what
-        * the spec says to do: the spec seems to want a warning only if no
-        * privilege bits actually change in the ACL. In practice that
-        * behavior seems much too noisy, as well as inconsistent with the
-        * GRANT case.)
-        */
-       this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
-       if (is_grant)
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("no privileges were granted")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
-                        errmsg("not all privileges were granted")));
-       }
-       else
-       {
-           if (this_privileges == 0)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("no privileges could be revoked")));
-           else if (!all_privs && this_privileges != privileges)
-               ereport(WARNING,
-                       (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
-                        errmsg("not all privileges could be revoked")));
-       }
+       this_privileges =
+           restrict_and_check_grant(istmt->is_grant, avail_goptions,
+                                    istmt->all_privs, istmt->privileges,
+                                    tblId, grantorId, ACL_KIND_TABLESPACE,
+                                    NameStr(pg_tablespace_tuple->spcname));
 
        /*
         * Generate new ACL.
@@ -1372,9 +1218,9 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
         */
        noldmembers = aclmembers(old_acl, &oldmembers);
 
-       new_acl = merge_acl_with_grant(old_acl, is_grant,
-                                      grant_option, behavior,
-                                      grantees, this_privileges,
+       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+                                      istmt->grant_option, istmt->behavior,
+                                      istmt->grantees, this_privileges,
                                       grantorId, ownerId);
 
        nnewmembers = aclmembers(new_acl, &newmembers);
@@ -1397,7 +1243,7 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
 
        /* Update the shared dependency ACL info */
        updateAclDependencies(TableSpaceRelationId, tblId,
-                             ownerId, is_grant,
+                             ownerId, istmt->is_grant,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
@@ -1583,6 +1429,34 @@ has_rolcatupdate(Oid roleid)
    return rolcatupdate;
 }
 
+/*
+ * Relay for the various pg_*_mask routines depending on object kind
+ */
+static AclMode
+pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
+          AclMode mask, AclMaskHow how)
+{
+   switch (objkind)
+   {
+       case ACL_KIND_CLASS:
+           return pg_class_aclmask(table_oid, roleid, mask, how);
+       case ACL_KIND_DATABASE:
+           return pg_database_aclmask(table_oid, roleid, mask, how);
+       case ACL_KIND_PROC:
+           return pg_proc_aclmask(table_oid, roleid, mask, how);
+       case ACL_KIND_LANGUAGE:
+           return pg_language_aclmask(table_oid, roleid, mask, how);
+       case ACL_KIND_NAMESPACE:
+           return pg_namespace_aclmask(table_oid, roleid, mask, how);
+       case ACL_KIND_TABLESPACE:
+           return pg_tablespace_aclmask(table_oid, roleid, mask, how);
+       default:
+           elog(ERROR, "unrecognized objkind: %d",
+                (int) objkind);
+           /* not reached, but keep compiler quiet */
+           return ACL_NO_RIGHTS;
+   }
+}
 
 /*
  * Exported routine for examining a user's privileges for a table
index 703f61391689ffb407aa7018dbc8c0cfcea6c9f3..faa64c22fce49bd259c47093c7329bb51f5b007e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.5 2005/11/22 18:17:08 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.6 2005/12/01 02:03:00 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1122,6 +1122,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
            {
                    ObjectAddress obj;
                    GrantObjectType objtype;
+                   InternalGrant istmt;
 
                    /* Shouldn't happen */
                case SHARED_DEPENDENCY_PIN:
@@ -1132,22 +1133,22 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                    switch (sdepForm->classid)
                    {
                        case RelationRelationId:
-                           objtype = ACL_OBJECT_RELATION;
+                           istmt.objtype = ACL_OBJECT_RELATION;
                            break;
                        case DatabaseRelationId:
-                           objtype = ACL_OBJECT_DATABASE;
+                           istmt.objtype = ACL_OBJECT_DATABASE;
                            break;
                        case ProcedureRelationId:
-                           objtype = ACL_OBJECT_FUNCTION;
+                           istmt.objtype = ACL_OBJECT_FUNCTION;
                            break;
                        case LanguageRelationId:
-                           objtype = ACL_OBJECT_LANGUAGE;
+                           istmt.objtype = ACL_OBJECT_LANGUAGE;
                            break;
                        case NamespaceRelationId:
-                           objtype = ACL_OBJECT_NAMESPACE;
+                           istmt.objtype = ACL_OBJECT_NAMESPACE;
                            break;
                        case TableSpaceRelationId:
-                           objtype = ACL_OBJECT_TABLESPACE;
+                           istmt.objtype = ACL_OBJECT_TABLESPACE;
                            break;
                        default:
                            elog(ERROR, "unexpected object type %d",
@@ -1156,11 +1157,15 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                            objtype = (GrantObjectType) 0;
                            break;
                    }
-
-                   ExecGrantStmt_oids(false, objtype,
-                                      list_make1_oid(sdepForm->objid), true,
-                                      ACL_NO_RIGHTS, list_make1_oid(roleid),
-                                      false, DROP_CASCADE);
+                   istmt.is_grant = false;
+                   istmt.objects = list_make1_oid(sdepForm->objid);
+                   istmt.all_privs = true;
+                   istmt.privileges = ACL_NO_RIGHTS;
+                   istmt.grantees = list_make1_oid(roleid);
+                   istmt.grant_option = false;
+                   istmt.behavior = DROP_CASCADE;
+
+                   ExecGrantStmt_oids(&istmt);
                    break;
                case SHARED_DEPENDENCY_OWNER:
 
index 04c56312144a55fa2ca355f789c514dae7265cf6..8e6cb95d2593b8f3bf1c11640dc6296d61ca18ca 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.90 2005/11/22 18:17:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.91 2005/12/01 02:03:01 alvherre Exp $
  *
  * NOTES
  *   An ACL array is simply an array of AclItems, representing the union
@@ -181,6 +181,26 @@ typedef enum AclObjectKind
    MAX_ACL_KIND                /* MUST BE LAST */
 } AclObjectKind;
 
+/*
+ * The information about one Grant/Revoke statement, in internal format: object
+ * and grantees names have been turned into Oids, the privilege list is an
+ * AclMode bitmask.  If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
+ * all_privs is true, it will be internally turned into the right kind of
+ * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
+ * InternalGrant struct!)
+ */
+typedef struct
+{
+   bool    is_grant;
+   GrantObjectType objtype;
+   List   *objects;
+   bool    all_privs;
+   AclMode privileges;
+   List   *grantees;
+   bool    grant_option;
+   DropBehavior behavior;
+} InternalGrant;
+
 /*
  * routines used internally
  */
@@ -221,9 +241,7 @@ 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 void ExecGrantStmt_oids(InternalGrant *istmt);
 
 extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
                 AclMode mask, AclMaskHow how);