LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 1524 1846 82.6 %
Date: 2025-09-01 10:17:37 Functions: 56 59 94.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * aclchk.c
       4             :  *    Routines to check access control permissions.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/aclchk.c
      12             :  *
      13             :  * NOTES
      14             :  *    See acl.h.
      15             :  *
      16             :  *    The xxx_aclmask() functions in this file are wrappers around
      17             :  *    acl.c's aclmask() function; see that for basic usage information.
      18             :  *    The wrapper functions add object-type-specific lookup capability.
      19             :  *    Generally, they will throw error if the object doesn't exist.
      20             :  *
      21             :  *    The xxx_aclmask_ext() functions add the ability to not throw
      22             :  *    error if the object doesn't exist.  If their "is_missing" argument
      23             :  *    isn't NULL, then when the object isn't found they will set
      24             :  *    *is_missing = true and return zero (no privileges) instead of
      25             :  *    throwing an error.  Caller must initialize *is_missing = false.
      26             :  *
      27             :  *    The xxx_aclcheck() functions are simplified wrappers around the
      28             :  *    corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
      29             :  *    if any of the privileges specified in "mode" are held, and otherwise
      30             :  *    a suitable error code (in practice, always ACLCHECK_NO_PRIV).
      31             :  *    Again, they will throw error if the object doesn't exist.
      32             :  *
      33             :  *    The xxx_aclcheck_ext() functions add the ability to not throw
      34             :  *    error if the object doesn't exist.  Their "is_missing" argument
      35             :  *    works similarly to the xxx_aclmask_ext() functions.
      36             :  *
      37             :  *-------------------------------------------------------------------------
      38             :  */
      39             : #include "postgres.h"
      40             : 
      41             : #include "access/genam.h"
      42             : #include "access/heapam.h"
      43             : #include "access/htup_details.h"
      44             : #include "access/sysattr.h"
      45             : #include "access/tableam.h"
      46             : #include "access/xact.h"
      47             : #include "catalog/binary_upgrade.h"
      48             : #include "catalog/catalog.h"
      49             : #include "catalog/dependency.h"
      50             : #include "catalog/indexing.h"
      51             : #include "catalog/objectaccess.h"
      52             : #include "catalog/pg_authid.h"
      53             : #include "catalog/pg_class.h"
      54             : #include "catalog/pg_database.h"
      55             : #include "catalog/pg_default_acl.h"
      56             : #include "catalog/pg_foreign_data_wrapper.h"
      57             : #include "catalog/pg_foreign_server.h"
      58             : #include "catalog/pg_init_privs.h"
      59             : #include "catalog/pg_language.h"
      60             : #include "catalog/pg_largeobject.h"
      61             : #include "catalog/pg_largeobject_metadata.h"
      62             : #include "catalog/pg_namespace.h"
      63             : #include "catalog/pg_parameter_acl.h"
      64             : #include "catalog/pg_proc.h"
      65             : #include "catalog/pg_tablespace.h"
      66             : #include "catalog/pg_type.h"
      67             : #include "commands/defrem.h"
      68             : #include "commands/event_trigger.h"
      69             : #include "commands/extension.h"
      70             : #include "commands/proclang.h"
      71             : #include "commands/tablespace.h"
      72             : #include "foreign/foreign.h"
      73             : #include "miscadmin.h"
      74             : #include "nodes/makefuncs.h"
      75             : #include "parser/parse_func.h"
      76             : #include "parser/parse_type.h"
      77             : #include "storage/lmgr.h"
      78             : #include "utils/acl.h"
      79             : #include "utils/aclchk_internal.h"
      80             : #include "utils/builtins.h"
      81             : #include "utils/fmgroids.h"
      82             : #include "utils/guc.h"
      83             : #include "utils/lsyscache.h"
      84             : #include "utils/rel.h"
      85             : #include "utils/syscache.h"
      86             : 
      87             : /*
      88             :  * Internal format used by ALTER DEFAULT PRIVILEGES.
      89             :  */
      90             : typedef struct
      91             : {
      92             :     Oid         roleid;         /* owning role */
      93             :     Oid         nspid;          /* namespace, or InvalidOid if none */
      94             :     /* remaining fields are same as in InternalGrant: */
      95             :     bool        is_grant;
      96             :     ObjectType  objtype;
      97             :     bool        all_privs;
      98             :     AclMode     privileges;
      99             :     List       *grantees;
     100             :     bool        grant_option;
     101             :     DropBehavior behavior;
     102             : } InternalDefaultACL;
     103             : 
     104             : /*
     105             :  * When performing a binary-upgrade, pg_dump will call a function to set
     106             :  * this variable to let us know that we need to populate the pg_init_privs
     107             :  * table for the GRANT/REVOKE commands while this variable is set to true.
     108             :  */
     109             : bool        binary_upgrade_record_init_privs = false;
     110             : 
     111             : static void ExecGrantStmt_oids(InternalGrant *istmt);
     112             : static void ExecGrant_Relation(InternalGrant *istmt);
     113             : static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
     114             :                              void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
     115             : static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
     116             : static void ExecGrant_Largeobject(InternalGrant *istmt);
     117             : static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
     118             : static void ExecGrant_Parameter(InternalGrant *istmt);
     119             : 
     120             : static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
     121             : static void SetDefaultACL(InternalDefaultACL *iacls);
     122             : 
     123             : static List *objectNamesToOids(ObjectType objtype, List *objnames,
     124             :                                bool is_grant);
     125             : static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
     126             : static List *getRelationsInNamespace(Oid namespaceId, char relkind);
     127             : static void expand_col_privileges(List *colnames, Oid table_oid,
     128             :                                   AclMode this_privileges,
     129             :                                   AclMode *col_privileges,
     130             :                                   int num_col_privileges);
     131             : static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
     132             :                                       AclMode this_privileges,
     133             :                                       AclMode *col_privileges,
     134             :                                       int num_col_privileges);
     135             : static AclMode string_to_privilege(const char *privname);
     136             : static const char *privilege_to_string(AclMode privilege);
     137             : static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
     138             :                                         bool all_privs, AclMode privileges,
     139             :                                         Oid objectId, Oid grantorId,
     140             :                                         ObjectType objtype, const char *objname,
     141             :                                         AttrNumber att_number, const char *colname);
     142             : static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
     143             :                           Oid roleid, AclMode mask, AclMaskHow how);
     144             : static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
     145             :                               AclMode mask, AclMaskHow how);
     146             : static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
     147             :                                   AclMode mask, AclMaskHow how,
     148             :                                   bool *is_missing);
     149             : static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
     150             :                                     Oid roleid, AclMode mask, AclMaskHow how);
     151             : static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
     152             :                                         Oid roleid, AclMode mask,
     153             :                                         AclMaskHow how, bool *is_missing);
     154             : static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
     155             :                                     AclMode mask, AclMaskHow how,
     156             :                                     bool *is_missing);
     157             : static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
     158             :                                         AclMode mask, AclMaskHow how);
     159             : static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
     160             :                                                AclMode mask, AclMaskHow how, Snapshot snapshot);
     161             : static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
     162             :                                         AclMode mask, AclMaskHow how,
     163             :                                         bool *is_missing);
     164             : static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
     165             :                                    AclMode mask, AclMaskHow how,
     166             :                                    bool *is_missing);
     167             : static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
     168             :                                     Acl *new_acl);
     169             : static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
     170             :                                           Acl *new_acl);
     171             : 
     172             : 
     173             : /*
     174             :  * If is_grant is true, adds the given privileges for the list of
     175             :  * grantees to the existing old_acl.  If is_grant is false, the
     176             :  * privileges for the given grantees are removed from old_acl.
     177             :  *
     178             :  * NB: the original old_acl is pfree'd.
     179             :  */
     180             : static Acl *
     181       79866 : merge_acl_with_grant(Acl *old_acl, bool is_grant,
     182             :                      bool grant_option, DropBehavior behavior,
     183             :                      List *grantees, AclMode privileges,
     184             :                      Oid grantorId, Oid ownerId)
     185             : {
     186             :     unsigned    modechg;
     187             :     ListCell   *j;
     188             :     Acl        *new_acl;
     189             : 
     190       79866 :     modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
     191             : 
     192       79866 :     new_acl = old_acl;
     193             : 
     194      159852 :     foreach(j, grantees)
     195             :     {
     196             :         AclItem     aclitem;
     197             :         Acl        *newer_acl;
     198             : 
     199       79998 :         aclitem.ai_grantee = lfirst_oid(j);
     200             : 
     201             :         /*
     202             :          * Grant options can only be granted to individual roles, not PUBLIC.
     203             :          * The reason is that if a user would re-grant a privilege that he
     204             :          * held through PUBLIC, and later the user is removed, the situation
     205             :          * is impossible to clean up.
     206             :          */
     207       79998 :         if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
     208           0 :             ereport(ERROR,
     209             :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     210             :                      errmsg("grant options can only be granted to roles")));
     211             : 
     212       79998 :         aclitem.ai_grantor = grantorId;
     213             : 
     214             :         /*
     215             :          * The asymmetry in the conditions here comes from the spec.  In
     216             :          * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
     217             :          * to grant both the basic privilege and its grant option. But in
     218             :          * REVOKE, plain revoke revokes both the basic privilege and its grant
     219             :          * option, while REVOKE GRANT OPTION revokes only the option.
     220             :          */
     221       79998 :         ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
     222             :                                    (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
     223             :                                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
     224             : 
     225       79998 :         newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
     226             : 
     227             :         /* avoid memory leak when there are many grantees */
     228       79986 :         pfree(new_acl);
     229       79986 :         new_acl = newer_acl;
     230             :     }
     231             : 
     232       79854 :     return new_acl;
     233             : }
     234             : 
     235             : /*
     236             :  * Restrict the privileges to what we can actually grant, and emit
     237             :  * the standards-mandated warning and error messages.
     238             :  */
     239             : static AclMode
     240       79638 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
     241             :                          AclMode privileges, Oid objectId, Oid grantorId,
     242             :                          ObjectType objtype, const char *objname,
     243             :                          AttrNumber att_number, const char *colname)
     244             : {
     245             :     AclMode     this_privileges;
     246             :     AclMode     whole_mask;
     247             : 
     248       79638 :     switch (objtype)
     249             :     {
     250       50432 :         case OBJECT_COLUMN:
     251       50432 :             whole_mask = ACL_ALL_RIGHTS_COLUMN;
     252       50432 :             break;
     253       18590 :         case OBJECT_TABLE:
     254       18590 :             whole_mask = ACL_ALL_RIGHTS_RELATION;
     255       18590 :             break;
     256         174 :         case OBJECT_SEQUENCE:
     257         174 :             whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
     258         174 :             break;
     259         356 :         case OBJECT_DATABASE:
     260         356 :             whole_mask = ACL_ALL_RIGHTS_DATABASE;
     261         356 :             break;
     262        9030 :         case OBJECT_FUNCTION:
     263        9030 :             whole_mask = ACL_ALL_RIGHTS_FUNCTION;
     264        9030 :             break;
     265          36 :         case OBJECT_LANGUAGE:
     266          36 :             whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
     267          36 :             break;
     268          80 :         case OBJECT_LARGEOBJECT:
     269          80 :             whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
     270          80 :             break;
     271         478 :         case OBJECT_SCHEMA:
     272         478 :             whole_mask = ACL_ALL_RIGHTS_SCHEMA;
     273         478 :             break;
     274           6 :         case OBJECT_TABLESPACE:
     275           6 :             whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
     276           6 :             break;
     277          94 :         case OBJECT_FDW:
     278          94 :             whole_mask = ACL_ALL_RIGHTS_FDW;
     279          94 :             break;
     280         102 :         case OBJECT_FOREIGN_SERVER:
     281         102 :             whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     282         102 :             break;
     283           0 :         case OBJECT_EVENT_TRIGGER:
     284           0 :             elog(ERROR, "grantable rights not supported for event triggers");
     285             :             /* not reached, but keep compiler quiet */
     286             :             return ACL_NO_RIGHTS;
     287         126 :         case OBJECT_TYPE:
     288         126 :             whole_mask = ACL_ALL_RIGHTS_TYPE;
     289         126 :             break;
     290         134 :         case OBJECT_PARAMETER_ACL:
     291         134 :             whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
     292         134 :             break;
     293           0 :         default:
     294           0 :             elog(ERROR, "unrecognized object type: %d", objtype);
     295             :             /* not reached, but keep compiler quiet */
     296             :             return ACL_NO_RIGHTS;
     297             :     }
     298             : 
     299             :     /*
     300             :      * If we found no grant options, consider whether to issue a hard error.
     301             :      * Per spec, having any privilege at all on the object will get you by
     302             :      * here.
     303             :      */
     304       79638 :     if (avail_goptions == ACL_NO_RIGHTS)
     305             :     {
     306          72 :         if (pg_aclmask(objtype, objectId, att_number, grantorId,
     307          72 :                        whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
     308             :                        ACLMASK_ANY) == ACL_NO_RIGHTS)
     309             :         {
     310          36 :             if (objtype == OBJECT_COLUMN && colname)
     311           0 :                 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
     312             :             else
     313          36 :                 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
     314             :         }
     315             :     }
     316             : 
     317             :     /*
     318             :      * Restrict the operation to what we can actually grant or revoke, and
     319             :      * issue a warning if appropriate.  (For REVOKE this isn't quite what the
     320             :      * spec says to do: the spec seems to want a warning only if no privilege
     321             :      * bits actually change in the ACL. In practice that behavior seems much
     322             :      * too noisy, as well as inconsistent with the GRANT case.)
     323             :      */
     324       79602 :     this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
     325       79602 :     if (is_grant)
     326             :     {
     327       17310 :         if (this_privileges == 0)
     328             :         {
     329          30 :             if (objtype == OBJECT_COLUMN && colname)
     330           0 :                 ereport(WARNING,
     331             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     332             :                          errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
     333             :                                 colname, objname)));
     334             :             else
     335          30 :                 ereport(WARNING,
     336             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     337             :                          errmsg("no privileges were granted for \"%s\"",
     338             :                                 objname)));
     339             :         }
     340       17280 :         else if (!all_privs && this_privileges != privileges)
     341             :         {
     342           6 :             if (objtype == OBJECT_COLUMN && colname)
     343           0 :                 ereport(WARNING,
     344             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     345             :                          errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
     346             :                                 colname, objname)));
     347             :             else
     348           6 :                 ereport(WARNING,
     349             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     350             :                          errmsg("not all privileges were granted for \"%s\"",
     351             :                                 objname)));
     352             :         }
     353             :     }
     354             :     else
     355             :     {
     356       62292 :         if (this_privileges == 0)
     357             :         {
     358           6 :             if (objtype == OBJECT_COLUMN && colname)
     359           0 :                 ereport(WARNING,
     360             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     361             :                          errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
     362             :                                 colname, objname)));
     363             :             else
     364           6 :                 ereport(WARNING,
     365             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     366             :                          errmsg("no privileges could be revoked for \"%s\"",
     367             :                                 objname)));
     368             :         }
     369       62286 :         else if (!all_privs && this_privileges != privileges)
     370             :         {
     371           0 :             if (objtype == OBJECT_COLUMN && colname)
     372           0 :                 ereport(WARNING,
     373             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     374             :                          errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
     375             :                                 colname, objname)));
     376             :             else
     377           0 :                 ereport(WARNING,
     378             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     379             :                          errmsg("not all privileges could be revoked for \"%s\"",
     380             :                                 objname)));
     381             :         }
     382             :     }
     383             : 
     384       79602 :     return this_privileges;
     385             : }
     386             : 
     387             : /*
     388             :  * Called to execute the utility commands GRANT and REVOKE
     389             :  */
     390             : void
     391       29238 : ExecuteGrantStmt(GrantStmt *stmt)
     392             : {
     393             :     InternalGrant istmt;
     394             :     ListCell   *cell;
     395             :     const char *errormsg;
     396             :     AclMode     all_privileges;
     397             : 
     398       29238 :     if (stmt->grantor)
     399             :     {
     400             :         Oid         grantor;
     401             : 
     402          18 :         grantor = get_rolespec_oid(stmt->grantor, false);
     403             : 
     404             :         /*
     405             :          * Currently, this clause is only for SQL compatibility, not very
     406             :          * interesting otherwise.
     407             :          */
     408          18 :         if (grantor != GetUserId())
     409           6 :             ereport(ERROR,
     410             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     411             :                      errmsg("grantor must be current user")));
     412             :     }
     413             : 
     414             :     /*
     415             :      * Turn the regular GrantStmt into the InternalGrant form.
     416             :      */
     417       29232 :     istmt.is_grant = stmt->is_grant;
     418       29232 :     istmt.objtype = stmt->objtype;
     419             : 
     420             :     /* Collect the OIDs of the target objects */
     421       29232 :     switch (stmt->targtype)
     422             :     {
     423       29202 :         case ACL_TARGET_OBJECT:
     424       58372 :             istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
     425       29202 :                                               stmt->is_grant);
     426       29170 :             break;
     427          30 :         case ACL_TARGET_ALL_IN_SCHEMA:
     428          30 :             istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
     429          30 :             break;
     430             :             /* ACL_TARGET_DEFAULTS should not be seen here */
     431           0 :         default:
     432           0 :             elog(ERROR, "unrecognized GrantStmt.targtype: %d",
     433             :                  (int) stmt->targtype);
     434             :     }
     435             : 
     436             :     /* all_privs to be filled below */
     437             :     /* privileges to be filled below */
     438       29200 :     istmt.col_privs = NIL;      /* may get filled below */
     439       29200 :     istmt.grantees = NIL;       /* filled below */
     440       29200 :     istmt.grant_option = stmt->grant_option;
     441       29200 :     istmt.behavior = stmt->behavior;
     442             : 
     443             :     /*
     444             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
     445             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
     446             :      * there shouldn't be any additional work needed to support this case.
     447             :      */
     448       58496 :     foreach(cell, stmt->grantees)
     449             :     {
     450       29302 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     451             :         Oid         grantee_uid;
     452             : 
     453       29302 :         switch (grantee->roletype)
     454             :         {
     455       24604 :             case ROLESPEC_PUBLIC:
     456       24604 :                 grantee_uid = ACL_ID_PUBLIC;
     457       24604 :                 break;
     458        4698 :             default:
     459        4698 :                 grantee_uid = get_rolespec_oid(grantee, false);
     460        4692 :                 break;
     461             :         }
     462       29296 :         istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
     463             :     }
     464             : 
     465             :     /*
     466             :      * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
     467             :      * bitmask.  Note: objtype can't be OBJECT_COLUMN.
     468             :      */
     469       29194 :     switch (stmt->objtype)
     470             :     {
     471       19002 :         case OBJECT_TABLE:
     472             : 
     473             :             /*
     474             :              * Because this might be a sequence, we test both relation and
     475             :              * sequence bits, and later do a more limited test when we know
     476             :              * the object type.
     477             :              */
     478       19002 :             all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
     479       19002 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     480       19002 :             break;
     481          22 :         case OBJECT_SEQUENCE:
     482          22 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
     483          22 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
     484          22 :             break;
     485         346 :         case OBJECT_DATABASE:
     486         346 :             all_privileges = ACL_ALL_RIGHTS_DATABASE;
     487         346 :             errormsg = gettext_noop("invalid privilege type %s for database");
     488         346 :             break;
     489          20 :         case OBJECT_DOMAIN:
     490          20 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     491          20 :             errormsg = gettext_noop("invalid privilege type %s for domain");
     492          20 :             break;
     493        8914 :         case OBJECT_FUNCTION:
     494        8914 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     495        8914 :             errormsg = gettext_noop("invalid privilege type %s for function");
     496        8914 :             break;
     497          42 :         case OBJECT_LANGUAGE:
     498          42 :             all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
     499          42 :             errormsg = gettext_noop("invalid privilege type %s for language");
     500          42 :             break;
     501          62 :         case OBJECT_LARGEOBJECT:
     502          62 :             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
     503          62 :             errormsg = gettext_noop("invalid privilege type %s for large object");
     504          62 :             break;
     505         362 :         case OBJECT_SCHEMA:
     506         362 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
     507         362 :             errormsg = gettext_noop("invalid privilege type %s for schema");
     508         362 :             break;
     509          48 :         case OBJECT_PROCEDURE:
     510          48 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     511          48 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
     512          48 :             break;
     513           6 :         case OBJECT_ROUTINE:
     514           6 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     515           6 :             errormsg = gettext_noop("invalid privilege type %s for routine");
     516           6 :             break;
     517           6 :         case OBJECT_TABLESPACE:
     518           6 :             all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
     519           6 :             errormsg = gettext_noop("invalid privilege type %s for tablespace");
     520           6 :             break;
     521         112 :         case OBJECT_TYPE:
     522         112 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     523         112 :             errormsg = gettext_noop("invalid privilege type %s for type");
     524         112 :             break;
     525          92 :         case OBJECT_FDW:
     526          92 :             all_privileges = ACL_ALL_RIGHTS_FDW;
     527          92 :             errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
     528          92 :             break;
     529          88 :         case OBJECT_FOREIGN_SERVER:
     530          88 :             all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     531          88 :             errormsg = gettext_noop("invalid privilege type %s for foreign server");
     532          88 :             break;
     533          72 :         case OBJECT_PARAMETER_ACL:
     534          72 :             all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
     535          72 :             errormsg = gettext_noop("invalid privilege type %s for parameter");
     536          72 :             break;
     537           0 :         default:
     538           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     539             :                  (int) stmt->objtype);
     540             :             /* keep compiler quiet */
     541             :             all_privileges = ACL_NO_RIGHTS;
     542             :             errormsg = NULL;
     543             :     }
     544             : 
     545       29194 :     if (stmt->privileges == NIL)
     546             :     {
     547        2710 :         istmt.all_privs = true;
     548             : 
     549             :         /*
     550             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
     551             :          * depending on the object type
     552             :          */
     553        2710 :         istmt.privileges = ACL_NO_RIGHTS;
     554             :     }
     555             :     else
     556             :     {
     557       26484 :         istmt.all_privs = false;
     558       26484 :         istmt.privileges = ACL_NO_RIGHTS;
     559             : 
     560       53480 :         foreach(cell, stmt->privileges)
     561             :         {
     562       27020 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
     563             :             AclMode     priv;
     564             : 
     565             :             /*
     566             :              * If it's a column-level specification, we just set it aside in
     567             :              * col_privs for the moment; but insist it's for a relation.
     568             :              */
     569       27020 :             if (privnode->cols)
     570             :             {
     571         442 :                 if (stmt->objtype != OBJECT_TABLE)
     572           0 :                     ereport(ERROR,
     573             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     574             :                              errmsg("column privileges are only valid for relations")));
     575         442 :                 istmt.col_privs = lappend(istmt.col_privs, privnode);
     576         442 :                 continue;
     577             :             }
     578             : 
     579       26578 :             if (privnode->priv_name == NULL) /* parser mistake? */
     580           0 :                 elog(ERROR, "AccessPriv node must specify privilege or columns");
     581       26578 :             priv = string_to_privilege(privnode->priv_name);
     582             : 
     583       26578 :             if (priv & ~((AclMode) all_privileges))
     584          24 :                 ereport(ERROR,
     585             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     586             :                          errmsg(errormsg, privilege_to_string(priv))));
     587             : 
     588       26554 :             istmt.privileges |= priv;
     589             :         }
     590             :     }
     591             : 
     592       29170 :     ExecGrantStmt_oids(&istmt);
     593       29098 : }
     594             : 
     595             : /*
     596             :  * ExecGrantStmt_oids
     597             :  *
     598             :  * Internal entry point for granting and revoking privileges.
     599             :  */
     600             : static void
     601       29396 : ExecGrantStmt_oids(InternalGrant *istmt)
     602             : {
     603       29396 :     switch (istmt->objtype)
     604             :     {
     605       19124 :         case OBJECT_TABLE:
     606             :         case OBJECT_SEQUENCE:
     607       19124 :             ExecGrant_Relation(istmt);
     608       19106 :             break;
     609         356 :         case OBJECT_DATABASE:
     610         356 :             ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
     611         356 :             break;
     612         138 :         case OBJECT_DOMAIN:
     613             :         case OBJECT_TYPE:
     614         138 :             ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
     615         120 :             break;
     616          94 :         case OBJECT_FDW:
     617          94 :             ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
     618          76 :             break;
     619         102 :         case OBJECT_FOREIGN_SERVER:
     620         102 :             ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
     621          90 :             break;
     622        8988 :         case OBJECT_FUNCTION:
     623             :         case OBJECT_PROCEDURE:
     624             :         case OBJECT_ROUTINE:
     625        8988 :             ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
     626        8988 :             break;
     627          42 :         case OBJECT_LANGUAGE:
     628          42 :             ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
     629          36 :             break;
     630          74 :         case OBJECT_LARGEOBJECT:
     631          74 :             ExecGrant_Largeobject(istmt);
     632          74 :             break;
     633         376 :         case OBJECT_SCHEMA:
     634         376 :             ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
     635         376 :             break;
     636           6 :         case OBJECT_TABLESPACE:
     637           6 :             ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
     638           6 :             break;
     639          96 :         case OBJECT_PARAMETER_ACL:
     640          96 :             ExecGrant_Parameter(istmt);
     641          96 :             break;
     642           0 :         default:
     643           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     644             :                  (int) istmt->objtype);
     645             :     }
     646             : 
     647             :     /*
     648             :      * Pass the info to event triggers about the just-executed GRANT.  Note
     649             :      * that we prefer to do it after actually executing it, because that gives
     650             :      * the functions a chance to adjust the istmt with privileges actually
     651             :      * granted.
     652             :      */
     653       29324 :     if (EventTriggerSupportsObjectType(istmt->objtype))
     654       28866 :         EventTriggerCollectGrant(istmt);
     655       29324 : }
     656             : 
     657             : /*
     658             :  * objectNamesToOids
     659             :  *
     660             :  * Turn a list of object names of a given type into an Oid list.
     661             :  *
     662             :  * XXX This function intentionally takes only an AccessShareLock.  In the face
     663             :  * of concurrent DDL, we might easily latch onto an old version of an object,
     664             :  * causing the GRANT or REVOKE statement to fail.  But it does prevent the
     665             :  * object from disappearing altogether.  To do better, we would need to use a
     666             :  * self-exclusive lock, perhaps ShareUpdateExclusiveLock, here and before
     667             :  * *every* CatalogTupleUpdate() of a row that GRANT/REVOKE can affect.
     668             :  * Besides that additional work, this could have operational costs.  For
     669             :  * example, it would make GRANT ALL TABLES IN SCHEMA terminate every
     670             :  * autovacuum running in the schema and consume a shared lock table entry per
     671             :  * table in the schema.  The user-visible benefit of that additional work is
     672             :  * just changing "ERROR: tuple concurrently updated" to blocking.  That's not
     673             :  * nothing, but it might not outweigh autovacuum termination and lock table
     674             :  * consumption spikes.
     675             :  */
     676             : static List *
     677       29202 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
     678             : {
     679       29202 :     List       *objects = NIL;
     680             :     ListCell   *cell;
     681       29202 :     const LOCKMODE lockmode = AccessShareLock;
     682             : 
     683             :     Assert(objnames != NIL);
     684             : 
     685       29202 :     switch (objtype)
     686             :     {
     687        9978 :         default:
     688             : 
     689             :             /*
     690             :              * For most object types, we use get_object_address() directly.
     691             :              */
     692       20064 :             foreach(cell, objnames)
     693             :             {
     694             :                 ObjectAddress address;
     695             : 
     696       10110 :                 address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
     697       10086 :                 objects = lappend_oid(objects, address.objectId);
     698             :             }
     699        9954 :             break;
     700             : 
     701       19012 :         case OBJECT_TABLE:
     702             :         case OBJECT_SEQUENCE:
     703             : 
     704             :             /*
     705             :              * Here, we don't use get_object_address().  It requires that the
     706             :              * specified object type match the actual type of the object, but
     707             :              * in GRANT/REVOKE, all table-like things are addressed as TABLE.
     708             :              */
     709       38078 :             foreach(cell, objnames)
     710             :             {
     711       19066 :                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
     712             :                 Oid         relOid;
     713             : 
     714       19066 :                 relOid = RangeVarGetRelid(relvar, lockmode, false);
     715       19066 :                 objects = lappend_oid(objects, relOid);
     716             :             }
     717       19012 :             break;
     718             : 
     719         138 :         case OBJECT_DOMAIN:
     720             :         case OBJECT_TYPE:
     721             : 
     722             :             /*
     723             :              * The parse representation of types and domains in privilege
     724             :              * targets is different from that expected by get_object_address()
     725             :              * (for parse conflict reasons), so we have to do a bit of
     726             :              * conversion here.
     727             :              */
     728         270 :             foreach(cell, objnames)
     729             :             {
     730         138 :                 List       *typname = (List *) lfirst(cell);
     731         138 :                 TypeName   *tn = makeTypeNameFromNameList(typname);
     732             :                 ObjectAddress address;
     733             :                 Relation    relation;
     734             : 
     735         138 :                 address = get_object_address(objtype, (Node *) tn, &relation, lockmode, false);
     736             :                 Assert(relation == NULL);
     737         132 :                 objects = lappend_oid(objects, address.objectId);
     738             :             }
     739         132 :             break;
     740             : 
     741          74 :         case OBJECT_PARAMETER_ACL:
     742             : 
     743             :             /*
     744             :              * Parameters are handled completely differently.
     745             :              */
     746         196 :             foreach(cell, objnames)
     747             :             {
     748             :                 /*
     749             :                  * In this code we represent a GUC by the OID of its entry in
     750             :                  * pg_parameter_acl, which we have to manufacture here if it
     751             :                  * doesn't exist yet.  (That's a hack for sure, but it avoids
     752             :                  * messing with all the GRANT/REVOKE infrastructure that
     753             :                  * expects to use OIDs for object identities.)  However, if
     754             :                  * this is a REVOKE, we can instead just ignore any GUCs that
     755             :                  * don't have such an entry, as they must not have any
     756             :                  * privileges needing removal.
     757             :                  */
     758         124 :                 char       *parameter = strVal(lfirst(cell));
     759         124 :                 Oid         parameterId = ParameterAclLookup(parameter, true);
     760             : 
     761         124 :                 if (!OidIsValid(parameterId) && is_grant)
     762             :                 {
     763          68 :                     parameterId = ParameterAclCreate(parameter);
     764             : 
     765             :                     /*
     766             :                      * Prevent error when processing duplicate objects, and
     767             :                      * make this new entry visible so that ExecGrant_Parameter
     768             :                      * can update it.
     769             :                      */
     770          66 :                     CommandCounterIncrement();
     771             :                 }
     772         122 :                 if (OidIsValid(parameterId))
     773         110 :                     objects = lappend_oid(objects, parameterId);
     774             :             }
     775          72 :             break;
     776             :     }
     777             : 
     778       29170 :     return objects;
     779             : }
     780             : 
     781             : /*
     782             :  * objectsInSchemaToOids
     783             :  *
     784             :  * Find all objects of a given type in specified schemas, and make a list
     785             :  * of their Oids.  We check USAGE privilege on the schemas, but there is
     786             :  * no privilege checking on the individual objects here.
     787             :  */
     788             : static List *
     789          30 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
     790             : {
     791          30 :     List       *objects = NIL;
     792             :     ListCell   *cell;
     793             : 
     794          60 :     foreach(cell, nspnames)
     795             :     {
     796          30 :         char       *nspname = strVal(lfirst(cell));
     797             :         Oid         namespaceId;
     798             :         List       *objs;
     799             : 
     800          30 :         namespaceId = LookupExplicitNamespace(nspname, false);
     801             : 
     802          30 :         switch (objtype)
     803             :         {
     804          12 :             case OBJECT_TABLE:
     805          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
     806          12 :                 objects = list_concat(objects, objs);
     807          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
     808          12 :                 objects = list_concat(objects, objs);
     809          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
     810          12 :                 objects = list_concat(objects, objs);
     811          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
     812          12 :                 objects = list_concat(objects, objs);
     813          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
     814          12 :                 objects = list_concat(objects, objs);
     815          12 :                 break;
     816           0 :             case OBJECT_SEQUENCE:
     817           0 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
     818           0 :                 objects = list_concat(objects, objs);
     819           0 :                 break;
     820          18 :             case OBJECT_FUNCTION:
     821             :             case OBJECT_PROCEDURE:
     822             :             case OBJECT_ROUTINE:
     823             :                 {
     824             :                     ScanKeyData key[2];
     825             :                     int         keycount;
     826             :                     Relation    rel;
     827             :                     TableScanDesc scan;
     828             :                     HeapTuple   tuple;
     829             : 
     830          18 :                     keycount = 0;
     831          18 :                     ScanKeyInit(&key[keycount++],
     832             :                                 Anum_pg_proc_pronamespace,
     833             :                                 BTEqualStrategyNumber, F_OIDEQ,
     834             :                                 ObjectIdGetDatum(namespaceId));
     835             : 
     836          18 :                     if (objtype == OBJECT_FUNCTION)
     837             :                         /* includes aggregates and window functions */
     838           6 :                         ScanKeyInit(&key[keycount++],
     839             :                                     Anum_pg_proc_prokind,
     840             :                                     BTEqualStrategyNumber, F_CHARNE,
     841             :                                     CharGetDatum(PROKIND_PROCEDURE));
     842          12 :                     else if (objtype == OBJECT_PROCEDURE)
     843           6 :                         ScanKeyInit(&key[keycount++],
     844             :                                     Anum_pg_proc_prokind,
     845             :                                     BTEqualStrategyNumber, F_CHAREQ,
     846             :                                     CharGetDatum(PROKIND_PROCEDURE));
     847             : 
     848          18 :                     rel = table_open(ProcedureRelationId, AccessShareLock);
     849          18 :                     scan = table_beginscan_catalog(rel, keycount, key);
     850             : 
     851          54 :                     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     852             :                     {
     853          36 :                         Oid         oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
     854             : 
     855          36 :                         objects = lappend_oid(objects, oid);
     856             :                     }
     857             : 
     858          18 :                     table_endscan(scan);
     859          18 :                     table_close(rel, AccessShareLock);
     860             :                 }
     861          18 :                 break;
     862           0 :             default:
     863             :                 /* should not happen */
     864           0 :                 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     865             :                      (int) objtype);
     866             :         }
     867             :     }
     868             : 
     869          30 :     return objects;
     870             : }
     871             : 
     872             : /*
     873             :  * getRelationsInNamespace
     874             :  *
     875             :  * Return Oid list of relations in given namespace filtered by relation kind
     876             :  */
     877             : static List *
     878          60 : getRelationsInNamespace(Oid namespaceId, char relkind)
     879             : {
     880          60 :     List       *relations = NIL;
     881             :     ScanKeyData key[2];
     882             :     Relation    rel;
     883             :     TableScanDesc scan;
     884             :     HeapTuple   tuple;
     885             : 
     886          60 :     ScanKeyInit(&key[0],
     887             :                 Anum_pg_class_relnamespace,
     888             :                 BTEqualStrategyNumber, F_OIDEQ,
     889             :                 ObjectIdGetDatum(namespaceId));
     890          60 :     ScanKeyInit(&key[1],
     891             :                 Anum_pg_class_relkind,
     892             :                 BTEqualStrategyNumber, F_CHAREQ,
     893             :                 CharGetDatum(relkind));
     894             : 
     895          60 :     rel = table_open(RelationRelationId, AccessShareLock);
     896          60 :     scan = table_beginscan_catalog(rel, 2, key);
     897             : 
     898          84 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     899             :     {
     900          24 :         Oid         oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
     901             : 
     902          24 :         relations = lappend_oid(relations, oid);
     903             :     }
     904             : 
     905          60 :     table_endscan(scan);
     906          60 :     table_close(rel, AccessShareLock);
     907             : 
     908          60 :     return relations;
     909             : }
     910             : 
     911             : 
     912             : /*
     913             :  * ALTER DEFAULT PRIVILEGES statement
     914             :  */
     915             : void
     916         206 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
     917             : {
     918         206 :     GrantStmt  *action = stmt->action;
     919             :     InternalDefaultACL iacls;
     920             :     ListCell   *cell;
     921         206 :     List       *rolespecs = NIL;
     922         206 :     List       *nspnames = NIL;
     923         206 :     DefElem    *drolespecs = NULL;
     924         206 :     DefElem    *dnspnames = NULL;
     925             :     AclMode     all_privileges;
     926             :     const char *errormsg;
     927             : 
     928             :     /* Deconstruct the "options" part of the statement */
     929         350 :     foreach(cell, stmt->options)
     930             :     {
     931         144 :         DefElem    *defel = (DefElem *) lfirst(cell);
     932             : 
     933         144 :         if (strcmp(defel->defname, "schemas") == 0)
     934             :         {
     935          60 :             if (dnspnames)
     936           0 :                 errorConflictingDefElem(defel, pstate);
     937          60 :             dnspnames = defel;
     938             :         }
     939          84 :         else if (strcmp(defel->defname, "roles") == 0)
     940             :         {
     941          84 :             if (drolespecs)
     942           0 :                 errorConflictingDefElem(defel, pstate);
     943          84 :             drolespecs = defel;
     944             :         }
     945             :         else
     946           0 :             elog(ERROR, "option \"%s\" not recognized", defel->defname);
     947             :     }
     948             : 
     949         206 :     if (dnspnames)
     950          60 :         nspnames = (List *) dnspnames->arg;
     951         206 :     if (drolespecs)
     952          84 :         rolespecs = (List *) drolespecs->arg;
     953             : 
     954             :     /* Prepare the InternalDefaultACL representation of the statement */
     955             :     /* roleid to be filled below */
     956             :     /* nspid to be filled in SetDefaultACLsInSchemas */
     957         206 :     iacls.is_grant = action->is_grant;
     958         206 :     iacls.objtype = action->objtype;
     959             :     /* all_privs to be filled below */
     960             :     /* privileges to be filled below */
     961         206 :     iacls.grantees = NIL;       /* filled below */
     962         206 :     iacls.grant_option = action->grant_option;
     963         206 :     iacls.behavior = action->behavior;
     964             : 
     965             :     /*
     966             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
     967             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
     968             :      * there shouldn't be any additional work needed to support this case.
     969             :      */
     970         418 :     foreach(cell, action->grantees)
     971             :     {
     972         212 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     973             :         Oid         grantee_uid;
     974             : 
     975         212 :         switch (grantee->roletype)
     976             :         {
     977          46 :             case ROLESPEC_PUBLIC:
     978          46 :                 grantee_uid = ACL_ID_PUBLIC;
     979          46 :                 break;
     980         166 :             default:
     981         166 :                 grantee_uid = get_rolespec_oid(grantee, false);
     982         166 :                 break;
     983             :         }
     984         212 :         iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
     985             :     }
     986             : 
     987             :     /*
     988             :      * Convert action->privileges, a list of privilege strings, into an
     989             :      * AclMode bitmask.
     990             :      */
     991         206 :     switch (action->objtype)
     992             :     {
     993          78 :         case OBJECT_TABLE:
     994          78 :             all_privileges = ACL_ALL_RIGHTS_RELATION;
     995          78 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     996          78 :             break;
     997           6 :         case OBJECT_SEQUENCE:
     998           6 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
     999           6 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
    1000           6 :             break;
    1001          22 :         case OBJECT_FUNCTION:
    1002          22 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1003          22 :             errormsg = gettext_noop("invalid privilege type %s for function");
    1004          22 :             break;
    1005           0 :         case OBJECT_PROCEDURE:
    1006           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1007           0 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
    1008           0 :             break;
    1009           0 :         case OBJECT_ROUTINE:
    1010           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1011           0 :             errormsg = gettext_noop("invalid privilege type %s for routine");
    1012           0 :             break;
    1013          34 :         case OBJECT_TYPE:
    1014          34 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
    1015          34 :             errormsg = gettext_noop("invalid privilege type %s for type");
    1016          34 :             break;
    1017          36 :         case OBJECT_SCHEMA:
    1018          36 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1019          36 :             errormsg = gettext_noop("invalid privilege type %s for schema");
    1020          36 :             break;
    1021          30 :         case OBJECT_LARGEOBJECT:
    1022          30 :             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    1023          30 :             errormsg = gettext_noop("invalid privilege type %s for large object");
    1024          30 :             break;
    1025           0 :         default:
    1026           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
    1027             :                  (int) action->objtype);
    1028             :             /* keep compiler quiet */
    1029             :             all_privileges = ACL_NO_RIGHTS;
    1030             :             errormsg = NULL;
    1031             :     }
    1032             : 
    1033         206 :     if (action->privileges == NIL)
    1034             :     {
    1035          78 :         iacls.all_privs = true;
    1036             : 
    1037             :         /*
    1038             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
    1039             :          * depending on the object type
    1040             :          */
    1041          78 :         iacls.privileges = ACL_NO_RIGHTS;
    1042             :     }
    1043             :     else
    1044             :     {
    1045         128 :         iacls.all_privs = false;
    1046         128 :         iacls.privileges = ACL_NO_RIGHTS;
    1047             : 
    1048         256 :         foreach(cell, action->privileges)
    1049             :         {
    1050         128 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
    1051             :             AclMode     priv;
    1052             : 
    1053         128 :             if (privnode->cols)
    1054           0 :                 ereport(ERROR,
    1055             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1056             :                          errmsg("default privileges cannot be set for columns")));
    1057             : 
    1058         128 :             if (privnode->priv_name == NULL) /* parser mistake? */
    1059           0 :                 elog(ERROR, "AccessPriv node must specify privilege");
    1060         128 :             priv = string_to_privilege(privnode->priv_name);
    1061             : 
    1062         128 :             if (priv & ~((AclMode) all_privileges))
    1063           0 :                 ereport(ERROR,
    1064             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1065             :                          errmsg(errormsg, privilege_to_string(priv))));
    1066             : 
    1067         128 :             iacls.privileges |= priv;
    1068             :         }
    1069             :     }
    1070             : 
    1071         206 :     if (rolespecs == NIL)
    1072             :     {
    1073             :         /* Set permissions for myself */
    1074         122 :         iacls.roleid = GetUserId();
    1075             : 
    1076         122 :         SetDefaultACLsInSchemas(&iacls, nspnames);
    1077             :     }
    1078             :     else
    1079             :     {
    1080             :         /* Look up the role OIDs and do permissions checks */
    1081             :         ListCell   *rolecell;
    1082             : 
    1083         168 :         foreach(rolecell, rolespecs)
    1084             :         {
    1085          84 :             RoleSpec   *rolespec = lfirst(rolecell);
    1086             : 
    1087          84 :             iacls.roleid = get_rolespec_oid(rolespec, false);
    1088             : 
    1089          84 :             if (!has_privs_of_role(GetUserId(), iacls.roleid))
    1090           0 :                 ereport(ERROR,
    1091             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1092             :                          errmsg("permission denied to change default privileges")));
    1093             : 
    1094          84 :             SetDefaultACLsInSchemas(&iacls, nspnames);
    1095             :         }
    1096             :     }
    1097         194 : }
    1098             : 
    1099             : /*
    1100             :  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
    1101             :  *
    1102             :  * All fields of *iacls except nspid were filled already
    1103             :  */
    1104             : static void
    1105         206 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
    1106             : {
    1107         206 :     if (nspnames == NIL)
    1108             :     {
    1109             :         /* Set database-wide permissions if no schema was specified */
    1110         146 :         iacls->nspid = InvalidOid;
    1111             : 
    1112         146 :         SetDefaultACL(iacls);
    1113             :     }
    1114             :     else
    1115             :     {
    1116             :         /* Look up the schema OIDs and set permissions for each one */
    1117             :         ListCell   *nspcell;
    1118             : 
    1119         114 :         foreach(nspcell, nspnames)
    1120             :         {
    1121          66 :             char       *nspname = strVal(lfirst(nspcell));
    1122             : 
    1123          66 :             iacls->nspid = get_namespace_oid(nspname, false);
    1124             : 
    1125             :             /*
    1126             :              * We used to insist that the target role have CREATE privileges
    1127             :              * on the schema, since without that it wouldn't be able to create
    1128             :              * an object for which these default privileges would apply.
    1129             :              * However, this check proved to be more confusing than helpful,
    1130             :              * and it also caused certain database states to not be
    1131             :              * dumpable/restorable, since revoking CREATE doesn't cause
    1132             :              * default privileges for the schema to go away.  So now, we just
    1133             :              * allow the ALTER; if the user lacks CREATE he'll find out when
    1134             :              * he tries to create an object.
    1135             :              */
    1136             : 
    1137          66 :             SetDefaultACL(iacls);
    1138             :         }
    1139             :     }
    1140         194 : }
    1141             : 
    1142             : 
    1143             : /*
    1144             :  * Create or update a pg_default_acl entry
    1145             :  */
    1146             : static void
    1147         248 : SetDefaultACL(InternalDefaultACL *iacls)
    1148             : {
    1149         248 :     AclMode     this_privileges = iacls->privileges;
    1150             :     char        objtype;
    1151             :     Relation    rel;
    1152             :     HeapTuple   tuple;
    1153             :     bool        isNew;
    1154             :     Acl        *def_acl;
    1155             :     Acl        *old_acl;
    1156             :     Acl        *new_acl;
    1157             :     HeapTuple   newtuple;
    1158             :     int         noldmembers;
    1159             :     int         nnewmembers;
    1160             :     Oid        *oldmembers;
    1161             :     Oid        *newmembers;
    1162             : 
    1163         248 :     rel = table_open(DefaultAclRelationId, RowExclusiveLock);
    1164             : 
    1165             :     /*
    1166             :      * The default for a global entry is the hard-wired default ACL for the
    1167             :      * particular object type.  The default for non-global entries is an empty
    1168             :      * ACL.  This must be so because global entries replace the hard-wired
    1169             :      * defaults, while others are added on.
    1170             :      */
    1171         248 :     if (!OidIsValid(iacls->nspid))
    1172         182 :         def_acl = acldefault(iacls->objtype, iacls->roleid);
    1173             :     else
    1174          66 :         def_acl = make_empty_acl();
    1175             : 
    1176             :     /*
    1177             :      * Convert ACL object type to pg_default_acl object type and handle
    1178             :      * all_privs option
    1179             :      */
    1180         248 :     switch (iacls->objtype)
    1181             :     {
    1182          90 :         case OBJECT_TABLE:
    1183          90 :             objtype = DEFACLOBJ_RELATION;
    1184          90 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1185          26 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1186          90 :             break;
    1187             : 
    1188          12 :         case OBJECT_SEQUENCE:
    1189          12 :             objtype = DEFACLOBJ_SEQUENCE;
    1190          12 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1191          12 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1192          12 :             break;
    1193             : 
    1194          28 :         case OBJECT_FUNCTION:
    1195          28 :             objtype = DEFACLOBJ_FUNCTION;
    1196          28 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1197          12 :                 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1198          28 :             break;
    1199             : 
    1200          40 :         case OBJECT_TYPE:
    1201          40 :             objtype = DEFACLOBJ_TYPE;
    1202          40 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1203          16 :                 this_privileges = ACL_ALL_RIGHTS_TYPE;
    1204          40 :             break;
    1205             : 
    1206          42 :         case OBJECT_SCHEMA:
    1207          42 :             if (OidIsValid(iacls->nspid))
    1208           6 :                 ereport(ERROR,
    1209             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1210             :                          errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
    1211          36 :             objtype = DEFACLOBJ_NAMESPACE;
    1212          36 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1213          24 :                 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1214          36 :             break;
    1215             : 
    1216          36 :         case OBJECT_LARGEOBJECT:
    1217          36 :             if (OidIsValid(iacls->nspid))
    1218           6 :                 ereport(ERROR,
    1219             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1220             :                          errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON LARGE OBJECTS")));
    1221          30 :             objtype = DEFACLOBJ_LARGEOBJECT;
    1222          30 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1223          18 :                 this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    1224          30 :             break;
    1225             : 
    1226           0 :         default:
    1227           0 :             elog(ERROR, "unrecognized object type: %d",
    1228             :                  (int) iacls->objtype);
    1229             :             objtype = 0;        /* keep compiler quiet */
    1230             :             break;
    1231             :     }
    1232             : 
    1233             :     /* Search for existing row for this object type in catalog */
    1234         236 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    1235             :                             ObjectIdGetDatum(iacls->roleid),
    1236             :                             ObjectIdGetDatum(iacls->nspid),
    1237             :                             CharGetDatum(objtype));
    1238             : 
    1239         236 :     if (HeapTupleIsValid(tuple))
    1240             :     {
    1241             :         Datum       aclDatum;
    1242             :         bool        isNull;
    1243             : 
    1244          90 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    1245             :                                    Anum_pg_default_acl_defaclacl,
    1246             :                                    &isNull);
    1247          90 :         if (!isNull)
    1248          90 :             old_acl = DatumGetAclPCopy(aclDatum);
    1249             :         else
    1250           0 :             old_acl = NULL;     /* this case shouldn't happen, probably */
    1251          90 :         isNew = false;
    1252             :     }
    1253             :     else
    1254             :     {
    1255         146 :         old_acl = NULL;
    1256         146 :         isNew = true;
    1257             :     }
    1258             : 
    1259         236 :     if (old_acl != NULL)
    1260             :     {
    1261             :         /*
    1262             :          * We need the members of both old and new ACLs so we can correct the
    1263             :          * shared dependency information.  Collect data before
    1264             :          * merge_acl_with_grant throws away old_acl.
    1265             :          */
    1266          90 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1267             :     }
    1268             :     else
    1269             :     {
    1270             :         /* If no or null entry, start with the default ACL value */
    1271         146 :         old_acl = aclcopy(def_acl);
    1272             :         /* There are no old member roles according to the catalogs */
    1273         146 :         noldmembers = 0;
    1274         146 :         oldmembers = NULL;
    1275             :     }
    1276             : 
    1277             :     /*
    1278             :      * Generate new ACL.  Grantor of rights is always the same as the target
    1279             :      * role.
    1280             :      */
    1281         236 :     new_acl = merge_acl_with_grant(old_acl,
    1282         236 :                                    iacls->is_grant,
    1283         236 :                                    iacls->grant_option,
    1284             :                                    iacls->behavior,
    1285             :                                    iacls->grantees,
    1286             :                                    this_privileges,
    1287             :                                    iacls->roleid,
    1288             :                                    iacls->roleid);
    1289             : 
    1290             :     /*
    1291             :      * If the result is the same as the default value, we do not need an
    1292             :      * explicit pg_default_acl entry, and should in fact remove the entry if
    1293             :      * it exists.  Must sort both arrays to compare properly.
    1294             :      */
    1295         236 :     aclitemsort(new_acl);
    1296         236 :     aclitemsort(def_acl);
    1297         236 :     if (aclequal(new_acl, def_acl))
    1298             :     {
    1299             :         /* delete old entry, if indeed there is one */
    1300          62 :         if (!isNew)
    1301             :         {
    1302             :             ObjectAddress myself;
    1303             : 
    1304             :             /*
    1305             :              * The dependency machinery will take care of removing all
    1306             :              * associated dependency entries.  We use DROP_RESTRICT since
    1307             :              * there shouldn't be anything depending on this entry.
    1308             :              */
    1309          60 :             myself.classId = DefaultAclRelationId;
    1310          60 :             myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1311          60 :             myself.objectSubId = 0;
    1312             : 
    1313          60 :             performDeletion(&myself, DROP_RESTRICT, 0);
    1314             :         }
    1315             :     }
    1316             :     else
    1317             :     {
    1318         174 :         Datum       values[Natts_pg_default_acl] = {0};
    1319         174 :         bool        nulls[Natts_pg_default_acl] = {0};
    1320         174 :         bool        replaces[Natts_pg_default_acl] = {0};
    1321             :         Oid         defAclOid;
    1322             : 
    1323         174 :         if (isNew)
    1324             :         {
    1325             :             /* insert new entry */
    1326         144 :             defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
    1327             :                                            Anum_pg_default_acl_oid);
    1328         144 :             values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
    1329         144 :             values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
    1330         144 :             values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
    1331         144 :             values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
    1332         144 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1333             : 
    1334         144 :             newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
    1335         144 :             CatalogTupleInsert(rel, newtuple);
    1336             :         }
    1337             :         else
    1338             :         {
    1339          30 :             defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1340             : 
    1341             :             /* update existing entry */
    1342          30 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1343          30 :             replaces[Anum_pg_default_acl_defaclacl - 1] = true;
    1344             : 
    1345          30 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
    1346             :                                          values, nulls, replaces);
    1347          30 :             CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    1348             :         }
    1349             : 
    1350             :         /* these dependencies don't change in an update */
    1351         174 :         if (isNew)
    1352             :         {
    1353             :             /* dependency on role */
    1354         144 :             recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
    1355             :                                     iacls->roleid);
    1356             : 
    1357             :             /* dependency on namespace */
    1358         144 :             if (OidIsValid(iacls->nspid))
    1359             :             {
    1360             :                 ObjectAddress myself,
    1361             :                             referenced;
    1362             : 
    1363          34 :                 myself.classId = DefaultAclRelationId;
    1364          34 :                 myself.objectId = defAclOid;
    1365          34 :                 myself.objectSubId = 0;
    1366             : 
    1367          34 :                 referenced.classId = NamespaceRelationId;
    1368          34 :                 referenced.objectId = iacls->nspid;
    1369          34 :                 referenced.objectSubId = 0;
    1370             : 
    1371          34 :                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
    1372             :             }
    1373             :         }
    1374             : 
    1375             :         /*
    1376             :          * Update the shared dependency ACL info
    1377             :          */
    1378         174 :         nnewmembers = aclmembers(new_acl, &newmembers);
    1379             : 
    1380         174 :         updateAclDependencies(DefaultAclRelationId,
    1381             :                               defAclOid, 0,
    1382             :                               iacls->roleid,
    1383             :                               noldmembers, oldmembers,
    1384             :                               nnewmembers, newmembers);
    1385             : 
    1386         174 :         if (isNew)
    1387         144 :             InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
    1388             :         else
    1389          30 :             InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
    1390             :     }
    1391             : 
    1392         236 :     if (HeapTupleIsValid(tuple))
    1393          90 :         ReleaseSysCache(tuple);
    1394             : 
    1395         236 :     table_close(rel, RowExclusiveLock);
    1396             : 
    1397             :     /* prevent error when processing duplicate objects */
    1398         236 :     CommandCounterIncrement();
    1399         236 : }
    1400             : 
    1401             : 
    1402             : /*
    1403             :  * RemoveRoleFromObjectACL
    1404             :  *
    1405             :  * Used by shdepDropOwned to remove mentions of a role in ACLs.
    1406             :  *
    1407             :  * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
    1408             :  * since the pg_shdepend record that caused us to call it certainly had one.
    1409             :  * If, for example, pg_shdepend records the existence of a permission on
    1410             :  * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
    1411             :  * mytable.  That gets the job done because (per SQL spec) such a REVOKE also
    1412             :  * revokes per-column permissions.  We could not recreate a situation where
    1413             :  * the role has table-level but not column-level permissions; but it's okay
    1414             :  * (for now anyway) because this is only used when we're dropping the role
    1415             :  * and so all its permissions everywhere must go away.  At worst it's a bit
    1416             :  * inefficient if the role has column permissions on several columns of the
    1417             :  * same table.
    1418             :  */
    1419             : void
    1420         262 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
    1421             : {
    1422         262 :     if (classid == DefaultAclRelationId)
    1423             :     {
    1424             :         InternalDefaultACL iacls;
    1425             :         Form_pg_default_acl pg_default_acl_tuple;
    1426             :         Relation    rel;
    1427             :         ScanKeyData skey[1];
    1428             :         SysScanDesc scan;
    1429             :         HeapTuple   tuple;
    1430             : 
    1431             :         /* first fetch info needed by SetDefaultACL */
    1432          36 :         rel = table_open(DefaultAclRelationId, AccessShareLock);
    1433             : 
    1434          36 :         ScanKeyInit(&skey[0],
    1435             :                     Anum_pg_default_acl_oid,
    1436             :                     BTEqualStrategyNumber, F_OIDEQ,
    1437             :                     ObjectIdGetDatum(objid));
    1438             : 
    1439          36 :         scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
    1440             :                                   NULL, 1, skey);
    1441             : 
    1442          36 :         tuple = systable_getnext(scan);
    1443             : 
    1444          36 :         if (!HeapTupleIsValid(tuple))
    1445           0 :             elog(ERROR, "could not find tuple for default ACL %u", objid);
    1446             : 
    1447          36 :         pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
    1448             : 
    1449          36 :         iacls.roleid = pg_default_acl_tuple->defaclrole;
    1450          36 :         iacls.nspid = pg_default_acl_tuple->defaclnamespace;
    1451             : 
    1452          36 :         switch (pg_default_acl_tuple->defaclobjtype)
    1453             :         {
    1454           6 :             case DEFACLOBJ_RELATION:
    1455           6 :                 iacls.objtype = OBJECT_TABLE;
    1456           6 :                 break;
    1457           6 :             case DEFACLOBJ_SEQUENCE:
    1458           6 :                 iacls.objtype = OBJECT_SEQUENCE;
    1459           6 :                 break;
    1460           6 :             case DEFACLOBJ_FUNCTION:
    1461           6 :                 iacls.objtype = OBJECT_FUNCTION;
    1462           6 :                 break;
    1463           6 :             case DEFACLOBJ_TYPE:
    1464           6 :                 iacls.objtype = OBJECT_TYPE;
    1465           6 :                 break;
    1466           6 :             case DEFACLOBJ_NAMESPACE:
    1467           6 :                 iacls.objtype = OBJECT_SCHEMA;
    1468           6 :                 break;
    1469           6 :             case DEFACLOBJ_LARGEOBJECT:
    1470           6 :                 iacls.objtype = OBJECT_LARGEOBJECT;
    1471           6 :                 break;
    1472           0 :             default:
    1473             :                 /* Shouldn't get here */
    1474           0 :                 elog(ERROR, "unexpected default ACL type: %d",
    1475             :                      (int) pg_default_acl_tuple->defaclobjtype);
    1476             :                 break;
    1477             :         }
    1478             : 
    1479          36 :         systable_endscan(scan);
    1480          36 :         table_close(rel, AccessShareLock);
    1481             : 
    1482          36 :         iacls.is_grant = false;
    1483          36 :         iacls.all_privs = true;
    1484          36 :         iacls.privileges = ACL_NO_RIGHTS;
    1485          36 :         iacls.grantees = list_make1_oid(roleid);
    1486          36 :         iacls.grant_option = false;
    1487          36 :         iacls.behavior = DROP_CASCADE;
    1488             : 
    1489             :         /* Do it */
    1490          36 :         SetDefaultACL(&iacls);
    1491             :     }
    1492             :     else
    1493             :     {
    1494             :         InternalGrant istmt;
    1495             : 
    1496         226 :         switch (classid)
    1497             :         {
    1498         100 :             case RelationRelationId:
    1499             :                 /* it's OK to use TABLE for a sequence */
    1500         100 :                 istmt.objtype = OBJECT_TABLE;
    1501         100 :                 break;
    1502          10 :             case DatabaseRelationId:
    1503          10 :                 istmt.objtype = OBJECT_DATABASE;
    1504          10 :                 break;
    1505           6 :             case TypeRelationId:
    1506           6 :                 istmt.objtype = OBJECT_TYPE;
    1507           6 :                 break;
    1508          38 :             case ProcedureRelationId:
    1509          38 :                 istmt.objtype = OBJECT_ROUTINE;
    1510          38 :                 break;
    1511           0 :             case LanguageRelationId:
    1512           0 :                 istmt.objtype = OBJECT_LANGUAGE;
    1513           0 :                 break;
    1514          18 :             case LargeObjectRelationId:
    1515          18 :                 istmt.objtype = OBJECT_LARGEOBJECT;
    1516          18 :                 break;
    1517          14 :             case NamespaceRelationId:
    1518          14 :                 istmt.objtype = OBJECT_SCHEMA;
    1519          14 :                 break;
    1520           0 :             case TableSpaceRelationId:
    1521           0 :                 istmt.objtype = OBJECT_TABLESPACE;
    1522           0 :                 break;
    1523          14 :             case ForeignServerRelationId:
    1524          14 :                 istmt.objtype = OBJECT_FOREIGN_SERVER;
    1525          14 :                 break;
    1526           2 :             case ForeignDataWrapperRelationId:
    1527           2 :                 istmt.objtype = OBJECT_FDW;
    1528           2 :                 break;
    1529          24 :             case ParameterAclRelationId:
    1530          24 :                 istmt.objtype = OBJECT_PARAMETER_ACL;
    1531          24 :                 break;
    1532           0 :             default:
    1533           0 :                 elog(ERROR, "unexpected object class %u", classid);
    1534             :                 break;
    1535             :         }
    1536         226 :         istmt.is_grant = false;
    1537         226 :         istmt.objects = list_make1_oid(objid);
    1538         226 :         istmt.all_privs = true;
    1539         226 :         istmt.privileges = ACL_NO_RIGHTS;
    1540         226 :         istmt.col_privs = NIL;
    1541         226 :         istmt.grantees = list_make1_oid(roleid);
    1542         226 :         istmt.grant_option = false;
    1543         226 :         istmt.behavior = DROP_CASCADE;
    1544             : 
    1545         226 :         ExecGrantStmt_oids(&istmt);
    1546             :     }
    1547         262 : }
    1548             : 
    1549             : 
    1550             : /*
    1551             :  * expand_col_privileges
    1552             :  *
    1553             :  * OR the specified privilege(s) into per-column array entries for each
    1554             :  * specified attribute.  The per-column array is indexed starting at
    1555             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1556             :  */
    1557             : static void
    1558         442 : expand_col_privileges(List *colnames, Oid table_oid,
    1559             :                       AclMode this_privileges,
    1560             :                       AclMode *col_privileges,
    1561             :                       int num_col_privileges)
    1562             : {
    1563             :     ListCell   *cell;
    1564             : 
    1565        2796 :     foreach(cell, colnames)
    1566             :     {
    1567        2354 :         char       *colname = strVal(lfirst(cell));
    1568             :         AttrNumber  attnum;
    1569             : 
    1570        2354 :         attnum = get_attnum(table_oid, colname);
    1571        2354 :         if (attnum == InvalidAttrNumber)
    1572           0 :             ereport(ERROR,
    1573             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1574             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    1575             :                             colname, get_rel_name(table_oid))));
    1576        2354 :         attnum -= FirstLowInvalidHeapAttributeNumber;
    1577        2354 :         if (attnum <= 0 || attnum >= num_col_privileges)
    1578           0 :             elog(ERROR, "column number out of range");    /* safety check */
    1579        2354 :         col_privileges[attnum] |= this_privileges;
    1580             :     }
    1581         442 : }
    1582             : 
    1583             : /*
    1584             :  * expand_all_col_privileges
    1585             :  *
    1586             :  * OR the specified privilege(s) into per-column array entries for each valid
    1587             :  * attribute of a relation.  The per-column array is indexed starting at
    1588             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1589             :  */
    1590             : static void
    1591        6532 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
    1592             :                           AclMode this_privileges,
    1593             :                           AclMode *col_privileges,
    1594             :                           int num_col_privileges)
    1595             : {
    1596             :     AttrNumber  curr_att;
    1597             : 
    1598             :     Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
    1599        6532 :     for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
    1600       67706 :          curr_att <= classForm->relnatts;
    1601       61174 :          curr_att++)
    1602             :     {
    1603             :         HeapTuple   attTuple;
    1604             :         bool        isdropped;
    1605             : 
    1606       61174 :         if (curr_att == InvalidAttrNumber)
    1607        6532 :             continue;
    1608             : 
    1609             :         /* Views don't have any system columns at all */
    1610       54642 :         if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
    1611        6516 :             continue;
    1612             : 
    1613       48126 :         attTuple = SearchSysCache2(ATTNUM,
    1614             :                                    ObjectIdGetDatum(table_oid),
    1615             :                                    Int16GetDatum(curr_att));
    1616       48126 :         if (!HeapTupleIsValid(attTuple))
    1617           0 :             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1618             :                  curr_att, table_oid);
    1619             : 
    1620       48126 :         isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
    1621             : 
    1622       48126 :         ReleaseSysCache(attTuple);
    1623             : 
    1624             :         /* ignore dropped columns */
    1625       48126 :         if (isdropped)
    1626           6 :             continue;
    1627             : 
    1628       48120 :         col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
    1629             :     }
    1630        6532 : }
    1631             : 
    1632             : /*
    1633             :  *  This processes attributes, but expects to be called from
    1634             :  *  ExecGrant_Relation, not directly from ExecuteGrantStmt.
    1635             :  */
    1636             : static void
    1637       50432 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
    1638             :                     AttrNumber attnum, Oid ownerId, AclMode col_privileges,
    1639             :                     Relation attRelation, const Acl *old_rel_acl)
    1640             : {
    1641             :     HeapTuple   attr_tuple;
    1642             :     Form_pg_attribute pg_attribute_tuple;
    1643             :     Acl        *old_acl;
    1644             :     Acl        *new_acl;
    1645             :     Acl        *merged_acl;
    1646             :     Datum       aclDatum;
    1647             :     bool        isNull;
    1648             :     Oid         grantorId;
    1649             :     AclMode     avail_goptions;
    1650             :     bool        need_update;
    1651             :     HeapTuple   newtuple;
    1652       50432 :     Datum       values[Natts_pg_attribute] = {0};
    1653       50432 :     bool        nulls[Natts_pg_attribute] = {0};
    1654       50432 :     bool        replaces[Natts_pg_attribute] = {0};
    1655             :     int         noldmembers;
    1656             :     int         nnewmembers;
    1657             :     Oid        *oldmembers;
    1658             :     Oid        *newmembers;
    1659             : 
    1660       50432 :     attr_tuple = SearchSysCache2(ATTNUM,
    1661             :                                  ObjectIdGetDatum(relOid),
    1662             :                                  Int16GetDatum(attnum));
    1663       50432 :     if (!HeapTupleIsValid(attr_tuple))
    1664           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1665             :              attnum, relOid);
    1666       50432 :     pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
    1667             : 
    1668             :     /*
    1669             :      * Get working copy of existing ACL. If there's no ACL, substitute the
    1670             :      * proper default.
    1671             :      */
    1672       50432 :     aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
    1673             :                                &isNull);
    1674       50432 :     if (isNull)
    1675             :     {
    1676       50122 :         old_acl = acldefault(OBJECT_COLUMN, ownerId);
    1677             :         /* There are no old member roles according to the catalogs */
    1678       50122 :         noldmembers = 0;
    1679       50122 :         oldmembers = NULL;
    1680             :     }
    1681             :     else
    1682             :     {
    1683         310 :         old_acl = DatumGetAclPCopy(aclDatum);
    1684             :         /* Get the roles mentioned in the existing ACL */
    1685         310 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1686             :     }
    1687             : 
    1688             :     /*
    1689             :      * In select_best_grantor we should consider existing table-level ACL bits
    1690             :      * as well as the per-column ACL.  Build a new ACL that is their
    1691             :      * concatenation.  (This is a bit cheap and dirty compared to merging them
    1692             :      * properly with no duplications, but it's all we need here.)
    1693             :      */
    1694       50432 :     merged_acl = aclconcat(old_rel_acl, old_acl);
    1695             : 
    1696             :     /* Determine ID to do the grant as, and available grant options */
    1697       50432 :     select_best_grantor(GetUserId(), col_privileges,
    1698             :                         merged_acl, ownerId,
    1699             :                         &grantorId, &avail_goptions);
    1700             : 
    1701       50432 :     pfree(merged_acl);
    1702             : 
    1703             :     /*
    1704             :      * Restrict the privileges to what we can actually grant, and emit the
    1705             :      * standards-mandated warning and error messages.  Note: we don't track
    1706             :      * whether the user actually used the ALL PRIVILEGES(columns) syntax for
    1707             :      * each column; we just approximate it by whether all the possible
    1708             :      * privileges are specified now.  Since the all_privs flag only determines
    1709             :      * whether a warning is issued, this seems close enough.
    1710             :      */
    1711             :     col_privileges =
    1712       50432 :         restrict_and_check_grant(istmt->is_grant, avail_goptions,
    1713             :                                  (col_privileges == ACL_ALL_RIGHTS_COLUMN),
    1714             :                                  col_privileges,
    1715             :                                  relOid, grantorId, OBJECT_COLUMN,
    1716             :                                  relname, attnum,
    1717       50432 :                                  NameStr(pg_attribute_tuple->attname));
    1718             : 
    1719             :     /*
    1720             :      * Generate new ACL.
    1721             :      */
    1722       50432 :     new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    1723       50432 :                                    istmt->grant_option,
    1724             :                                    istmt->behavior, istmt->grantees,
    1725             :                                    col_privileges, grantorId,
    1726             :                                    ownerId);
    1727             : 
    1728             :     /*
    1729             :      * We need the members of both old and new ACLs so we can correct the
    1730             :      * shared dependency information.
    1731             :      */
    1732       50432 :     nnewmembers = aclmembers(new_acl, &newmembers);
    1733             : 
    1734             :     /* finished building new ACL value, now insert it */
    1735             : 
    1736             :     /*
    1737             :      * If the updated ACL is empty, we can set attacl to null, and maybe even
    1738             :      * avoid an update of the pg_attribute row.  This is worth testing because
    1739             :      * we'll come through here multiple times for any relation-level REVOKE,
    1740             :      * even if there were never any column GRANTs.  Note we are assuming that
    1741             :      * the "default" ACL state for columns is empty.
    1742             :      */
    1743       50432 :     if (ACL_NUM(new_acl) > 0)
    1744             :     {
    1745        2378 :         values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
    1746        2378 :         need_update = true;
    1747             :     }
    1748             :     else
    1749             :     {
    1750       48054 :         nulls[Anum_pg_attribute_attacl - 1] = true;
    1751       48054 :         need_update = !isNull;
    1752             :     }
    1753       50432 :     replaces[Anum_pg_attribute_attacl - 1] = true;
    1754             : 
    1755       50432 :     if (need_update)
    1756             :     {
    1757        2474 :         newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
    1758             :                                      values, nulls, replaces);
    1759             : 
    1760        2474 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
    1761             : 
    1762             :         /* Update initial privileges for extensions */
    1763        2474 :         recordExtensionInitPriv(relOid, RelationRelationId, attnum,
    1764        2474 :                                 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
    1765             : 
    1766             :         /* Update the shared dependency ACL info */
    1767        2474 :         updateAclDependencies(RelationRelationId, relOid, attnum,
    1768             :                               ownerId,
    1769             :                               noldmembers, oldmembers,
    1770             :                               nnewmembers, newmembers);
    1771             :     }
    1772             : 
    1773       50432 :     pfree(new_acl);
    1774             : 
    1775       50432 :     ReleaseSysCache(attr_tuple);
    1776       50432 : }
    1777             : 
    1778             : /*
    1779             :  *  This processes both sequences and non-sequences.
    1780             :  */
    1781             : static void
    1782       19124 : ExecGrant_Relation(InternalGrant *istmt)
    1783             : {
    1784             :     Relation    relation;
    1785             :     Relation    attRelation;
    1786             :     ListCell   *cell;
    1787             : 
    1788       19124 :     relation = table_open(RelationRelationId, RowExclusiveLock);
    1789       19124 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
    1790             : 
    1791       38296 :     foreach(cell, istmt->objects)
    1792             :     {
    1793       19190 :         Oid         relOid = lfirst_oid(cell);
    1794             :         Datum       aclDatum;
    1795             :         Form_pg_class pg_class_tuple;
    1796             :         bool        isNull;
    1797             :         AclMode     this_privileges;
    1798             :         AclMode    *col_privileges;
    1799             :         int         num_col_privileges;
    1800             :         bool        have_col_privileges;
    1801             :         Acl        *old_acl;
    1802             :         Acl        *old_rel_acl;
    1803             :         int         noldmembers;
    1804             :         Oid        *oldmembers;
    1805             :         Oid         ownerId;
    1806             :         HeapTuple   tuple;
    1807             :         ListCell   *cell_colprivs;
    1808             : 
    1809       19190 :         tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
    1810       19190 :         if (!HeapTupleIsValid(tuple))
    1811           2 :             elog(ERROR, "cache lookup failed for relation %u", relOid);
    1812       19188 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    1813             : 
    1814             :         /* Not sensible to grant on an index */
    1815       19188 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    1816       19188 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    1817           0 :             ereport(ERROR,
    1818             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1819             :                      errmsg("\"%s\" is an index",
    1820             :                             NameStr(pg_class_tuple->relname))));
    1821             : 
    1822             :         /* Composite types aren't tables either */
    1823       19188 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    1824           0 :             ereport(ERROR,
    1825             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1826             :                      errmsg("\"%s\" is a composite type",
    1827             :                             NameStr(pg_class_tuple->relname))));
    1828             : 
    1829             :         /* Used GRANT SEQUENCE on a non-sequence? */
    1830       19188 :         if (istmt->objtype == OBJECT_SEQUENCE &&
    1831          22 :             pg_class_tuple->relkind != RELKIND_SEQUENCE)
    1832           0 :             ereport(ERROR,
    1833             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1834             :                      errmsg("\"%s\" is not a sequence",
    1835             :                             NameStr(pg_class_tuple->relname))));
    1836             : 
    1837             :         /* Adjust the default permissions based on object type */
    1838       19188 :         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    1839             :         {
    1840        2150 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1841          80 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1842             :             else
    1843        2070 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1844             :         }
    1845             :         else
    1846       17038 :             this_privileges = istmt->privileges;
    1847             : 
    1848             :         /*
    1849             :          * The GRANT TABLE syntax can be used for sequences and non-sequences,
    1850             :          * so we have to look at the relkind to determine the supported
    1851             :          * permissions.  The OR of table and sequence permissions were already
    1852             :          * checked.
    1853             :          */
    1854       19188 :         if (istmt->objtype == OBJECT_TABLE)
    1855             :         {
    1856       19166 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1857             :             {
    1858             :                 /*
    1859             :                  * For backward compatibility, just throw a warning for
    1860             :                  * invalid sequence permissions when using the non-sequence
    1861             :                  * GRANT syntax.
    1862             :                  */
    1863         152 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
    1864             :                 {
    1865             :                     /*
    1866             :                      * Mention the object name because the user needs to know
    1867             :                      * which operations succeeded.  This is required because
    1868             :                      * WARNING allows the command to continue.
    1869             :                      */
    1870           0 :                     ereport(WARNING,
    1871             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1872             :                              errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
    1873             :                                     NameStr(pg_class_tuple->relname))));
    1874           0 :                     this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
    1875             :                 }
    1876             :             }
    1877             :             else
    1878             :             {
    1879       19014 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
    1880             :                 {
    1881             :                     /*
    1882             :                      * USAGE is the only permission supported by sequences but
    1883             :                      * not by non-sequences.  Don't mention the object name
    1884             :                      * because we didn't in the combined TABLE | SEQUENCE
    1885             :                      * check.
    1886             :                      */
    1887           0 :                     ereport(ERROR,
    1888             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1889             :                              errmsg("invalid privilege type %s for table",
    1890             :                                     "USAGE")));
    1891             :                 }
    1892             :             }
    1893             :         }
    1894             : 
    1895             :         /*
    1896             :          * Set up array in which we'll accumulate any column privilege bits
    1897             :          * that need modification.  The array is indexed such that entry [0]
    1898             :          * corresponds to FirstLowInvalidHeapAttributeNumber.
    1899             :          */
    1900       19188 :         num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
    1901       19188 :         col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
    1902       19188 :         have_col_privileges = false;
    1903             : 
    1904             :         /*
    1905             :          * If we are revoking relation privileges that are also column
    1906             :          * privileges, we must implicitly revoke them from each column too,
    1907             :          * per SQL spec.  (We don't need to implicitly add column privileges
    1908             :          * during GRANT because the permissions-checking code always checks
    1909             :          * both relation and per-column privileges.)
    1910             :          */
    1911       19188 :         if (!istmt->is_grant &&
    1912        6590 :             (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
    1913             :         {
    1914        6532 :             expand_all_col_privileges(relOid, pg_class_tuple,
    1915             :                                       this_privileges & ACL_ALL_RIGHTS_COLUMN,
    1916             :                                       col_privileges,
    1917             :                                       num_col_privileges);
    1918        6532 :             have_col_privileges = true;
    1919             :         }
    1920             : 
    1921             :         /*
    1922             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    1923             :          * substitute the proper default.
    1924             :          */
    1925       19188 :         ownerId = pg_class_tuple->relowner;
    1926       19188 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    1927             :                                    &isNull);
    1928       19188 :         if (isNull)
    1929             :         {
    1930        8846 :             switch (pg_class_tuple->relkind)
    1931             :             {
    1932          92 :                 case RELKIND_SEQUENCE:
    1933          92 :                     old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
    1934          92 :                     break;
    1935        8754 :                 default:
    1936        8754 :                     old_acl = acldefault(OBJECT_TABLE, ownerId);
    1937        8754 :                     break;
    1938             :             }
    1939             :             /* There are no old member roles according to the catalogs */
    1940        8846 :             noldmembers = 0;
    1941        8846 :             oldmembers = NULL;
    1942             :         }
    1943             :         else
    1944             :         {
    1945       10342 :             old_acl = DatumGetAclPCopy(aclDatum);
    1946             :             /* Get the roles mentioned in the existing ACL */
    1947       10342 :             noldmembers = aclmembers(old_acl, &oldmembers);
    1948             :         }
    1949             : 
    1950             :         /* Need an extra copy of original rel ACL for column handling */
    1951       19188 :         old_rel_acl = aclcopy(old_acl);
    1952             : 
    1953             :         /*
    1954             :          * Handle relation-level privileges, if any were specified
    1955             :          */
    1956       19188 :         if (this_privileges != ACL_NO_RIGHTS)
    1957             :         {
    1958             :             AclMode     avail_goptions;
    1959             :             Acl        *new_acl;
    1960             :             Oid         grantorId;
    1961             :             HeapTuple   newtuple;
    1962       18764 :             Datum       values[Natts_pg_class] = {0};
    1963       18764 :             bool        nulls[Natts_pg_class] = {0};
    1964       18764 :             bool        replaces[Natts_pg_class] = {0};
    1965             :             int         nnewmembers;
    1966             :             Oid        *newmembers;
    1967             :             ObjectType  objtype;
    1968             : 
    1969             :             /* Determine ID to do the grant as, and available grant options */
    1970       18764 :             select_best_grantor(GetUserId(), this_privileges,
    1971             :                                 old_acl, ownerId,
    1972             :                                 &grantorId, &avail_goptions);
    1973             : 
    1974       18764 :             switch (pg_class_tuple->relkind)
    1975             :             {
    1976         174 :                 case RELKIND_SEQUENCE:
    1977         174 :                     objtype = OBJECT_SEQUENCE;
    1978         174 :                     break;
    1979       18590 :                 default:
    1980       18590 :                     objtype = OBJECT_TABLE;
    1981       18590 :                     break;
    1982             :             }
    1983             : 
    1984             :             /*
    1985             :              * Restrict the privileges to what we can actually grant, and emit
    1986             :              * the standards-mandated warning and error messages.
    1987             :              */
    1988             :             this_privileges =
    1989       18764 :                 restrict_and_check_grant(istmt->is_grant, avail_goptions,
    1990       18764 :                                          istmt->all_privs, this_privileges,
    1991             :                                          relOid, grantorId, objtype,
    1992       18764 :                                          NameStr(pg_class_tuple->relname),
    1993             :                                          0, NULL);
    1994             : 
    1995             :             /*
    1996             :              * Generate new ACL.
    1997             :              */
    1998       18758 :             new_acl = merge_acl_with_grant(old_acl,
    1999       18758 :                                            istmt->is_grant,
    2000       18758 :                                            istmt->grant_option,
    2001             :                                            istmt->behavior,
    2002             :                                            istmt->grantees,
    2003             :                                            this_privileges,
    2004             :                                            grantorId,
    2005             :                                            ownerId);
    2006             : 
    2007             :             /*
    2008             :              * We need the members of both old and new ACLs so we can correct
    2009             :              * the shared dependency information.
    2010             :              */
    2011       18752 :             nnewmembers = aclmembers(new_acl, &newmembers);
    2012             : 
    2013             :             /* finished building new ACL value, now insert it */
    2014       18752 :             replaces[Anum_pg_class_relacl - 1] = true;
    2015       18752 :             values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
    2016             : 
    2017       18752 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2018             :                                          values, nulls, replaces);
    2019             : 
    2020       18752 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2021       18748 :             UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
    2022             : 
    2023             :             /* Update initial privileges for extensions */
    2024       18748 :             recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
    2025             : 
    2026             :             /* Update the shared dependency ACL info */
    2027       18748 :             updateAclDependencies(RelationRelationId, relOid, 0,
    2028             :                                   ownerId,
    2029             :                                   noldmembers, oldmembers,
    2030             :                                   nnewmembers, newmembers);
    2031             : 
    2032       18748 :             pfree(new_acl);
    2033             :         }
    2034             :         else
    2035         424 :             UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
    2036             : 
    2037             :         /*
    2038             :          * Handle column-level privileges, if any were specified or implied.
    2039             :          * We first expand the user-specified column privileges into the
    2040             :          * array, and then iterate over all nonempty array entries.
    2041             :          */
    2042       19614 :         foreach(cell_colprivs, istmt->col_privs)
    2043             :         {
    2044         442 :             AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
    2045             : 
    2046         442 :             if (col_privs->priv_name == NULL)
    2047          18 :                 this_privileges = ACL_ALL_RIGHTS_COLUMN;
    2048             :             else
    2049         424 :                 this_privileges = string_to_privilege(col_privs->priv_name);
    2050             : 
    2051         442 :             if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
    2052           0 :                 ereport(ERROR,
    2053             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2054             :                          errmsg("invalid privilege type %s for column",
    2055             :                                 privilege_to_string(this_privileges))));
    2056             : 
    2057         442 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
    2058           0 :                 this_privileges & ~((AclMode) ACL_SELECT))
    2059             :             {
    2060             :                 /*
    2061             :                  * The only column privilege allowed on sequences is SELECT.
    2062             :                  * This is a warning not error because we do it that way for
    2063             :                  * relation-level privileges.
    2064             :                  */
    2065           0 :                 ereport(WARNING,
    2066             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2067             :                          errmsg("sequence \"%s\" only supports SELECT column privileges",
    2068             :                                 NameStr(pg_class_tuple->relname))));
    2069             : 
    2070           0 :                 this_privileges &= (AclMode) ACL_SELECT;
    2071             :             }
    2072             : 
    2073         442 :             expand_col_privileges(col_privs->cols, relOid,
    2074             :                                   this_privileges,
    2075             :                                   col_privileges,
    2076             :                                   num_col_privileges);
    2077         442 :             have_col_privileges = true;
    2078             :         }
    2079             : 
    2080       19172 :         if (have_col_privileges)
    2081             :         {
    2082             :             AttrNumber  i;
    2083             : 
    2084       81274 :             for (i = 0; i < num_col_privileges; i++)
    2085             :             {
    2086       74318 :                 if (col_privileges[i] == ACL_NO_RIGHTS)
    2087       23886 :                     continue;
    2088       50432 :                 ExecGrant_Attribute(istmt,
    2089             :                                     relOid,
    2090       50432 :                                     NameStr(pg_class_tuple->relname),
    2091       50432 :                                     i + FirstLowInvalidHeapAttributeNumber,
    2092             :                                     ownerId,
    2093       50432 :                                     col_privileges[i],
    2094             :                                     attRelation,
    2095             :                                     old_rel_acl);
    2096             :             }
    2097             :         }
    2098             : 
    2099       19172 :         pfree(old_rel_acl);
    2100       19172 :         pfree(col_privileges);
    2101             : 
    2102       19172 :         ReleaseSysCache(tuple);
    2103             : 
    2104             :         /* prevent error when processing duplicate objects */
    2105       19172 :         CommandCounterIncrement();
    2106             :     }
    2107             : 
    2108       19106 :     table_close(attRelation, RowExclusiveLock);
    2109       19106 :     table_close(relation, RowExclusiveLock);
    2110       19106 : }
    2111             : 
    2112             : static void
    2113       10102 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
    2114             :                  void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
    2115             : {
    2116             :     int         cacheid;
    2117             :     Relation    relation;
    2118             :     ListCell   *cell;
    2119             : 
    2120       10102 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2121         742 :         istmt->privileges = default_privs;
    2122             : 
    2123       10102 :     cacheid = get_object_catcache_oid(classid);
    2124             : 
    2125       10102 :     relation = table_open(classid, RowExclusiveLock);
    2126             : 
    2127       20294 :     foreach(cell, istmt->objects)
    2128             :     {
    2129       10246 :         Oid         objectid = lfirst_oid(cell);
    2130             :         Datum       aclDatum;
    2131             :         Datum       nameDatum;
    2132             :         bool        isNull;
    2133             :         AclMode     avail_goptions;
    2134             :         AclMode     this_privileges;
    2135             :         Acl        *old_acl;
    2136             :         Acl        *new_acl;
    2137             :         Oid         grantorId;
    2138             :         Oid         ownerId;
    2139             :         HeapTuple   tuple;
    2140             :         HeapTuple   newtuple;
    2141       10246 :         Datum      *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
    2142       10246 :         bool       *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2143       10246 :         bool       *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2144             :         int         noldmembers;
    2145             :         int         nnewmembers;
    2146             :         Oid        *oldmembers;
    2147             :         Oid        *newmembers;
    2148             : 
    2149       10246 :         tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
    2150       10246 :         if (!HeapTupleIsValid(tuple))
    2151           0 :             elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
    2152             : 
    2153             :         /*
    2154             :          * Additional object-type-specific checks
    2155             :          */
    2156       10246 :         if (object_check)
    2157         180 :             object_check(istmt, tuple);
    2158             : 
    2159             :         /*
    2160             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2161             :          * substitute the proper default.
    2162             :          */
    2163       10228 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    2164             :                                                           tuple,
    2165       10228 :                                                           get_object_attnum_owner(classid)));
    2166       10228 :         aclDatum = SysCacheGetAttr(cacheid,
    2167             :                                    tuple,
    2168       10228 :                                    get_object_attnum_acl(classid),
    2169             :                                    &isNull);
    2170       10228 :         if (isNull)
    2171             :         {
    2172        7832 :             old_acl = acldefault(get_object_type(classid, objectid), ownerId);
    2173             :             /* There are no old member roles according to the catalogs */
    2174        7832 :             noldmembers = 0;
    2175        7832 :             oldmembers = NULL;
    2176             :         }
    2177             :         else
    2178             :         {
    2179        2396 :             old_acl = DatumGetAclPCopy(aclDatum);
    2180             :             /* Get the roles mentioned in the existing ACL */
    2181        2396 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2182             :         }
    2183             : 
    2184             :         /* Determine ID to do the grant as, and available grant options */
    2185       10228 :         select_best_grantor(GetUserId(), istmt->privileges,
    2186             :                             old_acl, ownerId,
    2187             :                             &grantorId, &avail_goptions);
    2188             : 
    2189       10228 :         nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
    2190       10228 :                                            get_object_attnum_name(classid));
    2191             : 
    2192             :         /*
    2193             :          * Restrict the privileges to what we can actually grant, and emit the
    2194             :          * standards-mandated warning and error messages.
    2195             :          */
    2196             :         this_privileges =
    2197       20456 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2198       10228 :                                      istmt->all_privs, istmt->privileges,
    2199             :                                      objectid, grantorId, get_object_type(classid, objectid),
    2200       10228 :                                      NameStr(*DatumGetName(nameDatum)),
    2201             :                                      0, NULL);
    2202             : 
    2203             :         /*
    2204             :          * Generate new ACL.
    2205             :          */
    2206       10198 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2207       10198 :                                        istmt->grant_option, istmt->behavior,
    2208             :                                        istmt->grantees, this_privileges,
    2209             :                                        grantorId, ownerId);
    2210             : 
    2211             :         /*
    2212             :          * We need the members of both old and new ACLs so we can correct the
    2213             :          * shared dependency information.
    2214             :          */
    2215       10192 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2216             : 
    2217             :         /* finished building new ACL value, now insert it */
    2218       10192 :         replaces[get_object_attnum_acl(classid) - 1] = true;
    2219       10192 :         values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
    2220             : 
    2221       10192 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2222             :                                      nulls, replaces);
    2223             : 
    2224       10192 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2225       10192 :         UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
    2226             : 
    2227             :         /* Update initial privileges for extensions */
    2228       10192 :         recordExtensionInitPriv(objectid, classid, 0, new_acl);
    2229             : 
    2230             :         /* Update the shared dependency ACL info */
    2231       10192 :         updateAclDependencies(classid,
    2232             :                               objectid, 0,
    2233             :                               ownerId,
    2234             :                               noldmembers, oldmembers,
    2235             :                               nnewmembers, newmembers);
    2236             : 
    2237       10192 :         ReleaseSysCache(tuple);
    2238             : 
    2239       10192 :         pfree(new_acl);
    2240             : 
    2241             :         /* prevent error when processing duplicate objects */
    2242       10192 :         CommandCounterIncrement();
    2243             :     }
    2244             : 
    2245       10048 :     table_close(relation, RowExclusiveLock);
    2246       10048 : }
    2247             : 
    2248             : static void
    2249          42 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
    2250             : {
    2251             :     Form_pg_language pg_language_tuple;
    2252             : 
    2253          42 :     pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
    2254             : 
    2255          42 :     if (!pg_language_tuple->lanpltrusted)
    2256           6 :         ereport(ERROR,
    2257             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2258             :                  errmsg("language \"%s\" is not trusted",
    2259             :                         NameStr(pg_language_tuple->lanname)),
    2260             :                  errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
    2261             :                            "because only superusers can use untrusted languages.")));
    2262          36 : }
    2263             : 
    2264             : static void
    2265          74 : ExecGrant_Largeobject(InternalGrant *istmt)
    2266             : {
    2267             :     Relation    relation;
    2268             :     ListCell   *cell;
    2269             : 
    2270          74 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2271          44 :         istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    2272             : 
    2273          74 :     relation = table_open(LargeObjectMetadataRelationId,
    2274             :                           RowExclusiveLock);
    2275             : 
    2276         154 :     foreach(cell, istmt->objects)
    2277             :     {
    2278          80 :         Oid         loid = lfirst_oid(cell);
    2279             :         Form_pg_largeobject_metadata form_lo_meta;
    2280             :         char        loname[NAMEDATALEN];
    2281             :         Datum       aclDatum;
    2282             :         bool        isNull;
    2283             :         AclMode     avail_goptions;
    2284             :         AclMode     this_privileges;
    2285             :         Acl        *old_acl;
    2286             :         Acl        *new_acl;
    2287             :         Oid         grantorId;
    2288             :         Oid         ownerId;
    2289             :         HeapTuple   newtuple;
    2290          80 :         Datum       values[Natts_pg_largeobject_metadata] = {0};
    2291          80 :         bool        nulls[Natts_pg_largeobject_metadata] = {0};
    2292          80 :         bool        replaces[Natts_pg_largeobject_metadata] = {0};
    2293             :         int         noldmembers;
    2294             :         int         nnewmembers;
    2295             :         Oid        *oldmembers;
    2296             :         Oid        *newmembers;
    2297             :         ScanKeyData entry[1];
    2298             :         SysScanDesc scan;
    2299             :         HeapTuple   tuple;
    2300             : 
    2301             :         /* There's no syscache for pg_largeobject_metadata */
    2302          80 :         ScanKeyInit(&entry[0],
    2303             :                     Anum_pg_largeobject_metadata_oid,
    2304             :                     BTEqualStrategyNumber, F_OIDEQ,
    2305             :                     ObjectIdGetDatum(loid));
    2306             : 
    2307          80 :         scan = systable_beginscan(relation,
    2308             :                                   LargeObjectMetadataOidIndexId, true,
    2309             :                                   NULL, 1, entry);
    2310             : 
    2311          80 :         tuple = systable_getnext(scan);
    2312          80 :         if (!HeapTupleIsValid(tuple))
    2313           0 :             elog(ERROR, "could not find tuple for large object %u", loid);
    2314             : 
    2315          80 :         form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
    2316             : 
    2317             :         /*
    2318             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2319             :          * substitute the proper default.
    2320             :          */
    2321          80 :         ownerId = form_lo_meta->lomowner;
    2322          80 :         aclDatum = heap_getattr(tuple,
    2323             :                                 Anum_pg_largeobject_metadata_lomacl,
    2324             :                                 RelationGetDescr(relation), &isNull);
    2325          80 :         if (isNull)
    2326             :         {
    2327          44 :             old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    2328             :             /* There are no old member roles according to the catalogs */
    2329          44 :             noldmembers = 0;
    2330          44 :             oldmembers = NULL;
    2331             :         }
    2332             :         else
    2333             :         {
    2334          36 :             old_acl = DatumGetAclPCopy(aclDatum);
    2335             :             /* Get the roles mentioned in the existing ACL */
    2336          36 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2337             :         }
    2338             : 
    2339             :         /* Determine ID to do the grant as, and available grant options */
    2340          80 :         select_best_grantor(GetUserId(), istmt->privileges,
    2341             :                             old_acl, ownerId,
    2342             :                             &grantorId, &avail_goptions);
    2343             : 
    2344             :         /*
    2345             :          * Restrict the privileges to what we can actually grant, and emit the
    2346             :          * standards-mandated warning and error messages.
    2347             :          */
    2348          80 :         snprintf(loname, sizeof(loname), "large object %u", loid);
    2349             :         this_privileges =
    2350          80 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2351          80 :                                      istmt->all_privs, istmt->privileges,
    2352             :                                      loid, grantorId, OBJECT_LARGEOBJECT,
    2353             :                                      loname, 0, NULL);
    2354             : 
    2355             :         /*
    2356             :          * Generate new ACL.
    2357             :          */
    2358          80 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2359          80 :                                        istmt->grant_option, istmt->behavior,
    2360             :                                        istmt->grantees, this_privileges,
    2361             :                                        grantorId, ownerId);
    2362             : 
    2363             :         /*
    2364             :          * We need the members of both old and new ACLs so we can correct the
    2365             :          * shared dependency information.
    2366             :          */
    2367          80 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2368             : 
    2369             :         /* finished building new ACL value, now insert it */
    2370          80 :         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
    2371             :         values[Anum_pg_largeobject_metadata_lomacl - 1]
    2372          80 :             = PointerGetDatum(new_acl);
    2373             : 
    2374          80 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2375             :                                      values, nulls, replaces);
    2376             : 
    2377          80 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2378             : 
    2379             :         /* Update initial privileges for extensions */
    2380          80 :         recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
    2381             : 
    2382             :         /* Update the shared dependency ACL info */
    2383          80 :         updateAclDependencies(LargeObjectRelationId,
    2384             :                               form_lo_meta->oid, 0,
    2385             :                               ownerId,
    2386             :                               noldmembers, oldmembers,
    2387             :                               nnewmembers, newmembers);
    2388             : 
    2389          80 :         systable_endscan(scan);
    2390             : 
    2391          80 :         pfree(new_acl);
    2392             : 
    2393             :         /* prevent error when processing duplicate objects */
    2394          80 :         CommandCounterIncrement();
    2395             :     }
    2396             : 
    2397          74 :     table_close(relation, RowExclusiveLock);
    2398          74 : }
    2399             : 
    2400             : static void
    2401         138 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
    2402             : {
    2403             :     Form_pg_type pg_type_tuple;
    2404             : 
    2405         138 :     pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
    2406             : 
    2407             :     /* Disallow GRANT on dependent types */
    2408         138 :     if (IsTrueArrayType(pg_type_tuple))
    2409           6 :         ereport(ERROR,
    2410             :                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2411             :                  errmsg("cannot set privileges of array types"),
    2412             :                  errhint("Set the privileges of the element type instead.")));
    2413         132 :     if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
    2414           6 :         ereport(ERROR,
    2415             :                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2416             :                  errmsg("cannot set privileges of multirange types"),
    2417             :                  errhint("Set the privileges of the range type instead.")));
    2418         126 : }
    2419             : 
    2420             : static void
    2421          96 : ExecGrant_Parameter(InternalGrant *istmt)
    2422             : {
    2423             :     Relation    relation;
    2424             :     ListCell   *cell;
    2425             : 
    2426          96 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2427          42 :         istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
    2428             : 
    2429          96 :     relation = table_open(ParameterAclRelationId, RowExclusiveLock);
    2430             : 
    2431         230 :     foreach(cell, istmt->objects)
    2432             :     {
    2433         134 :         Oid         parameterId = lfirst_oid(cell);
    2434             :         Datum       nameDatum;
    2435             :         const char *parname;
    2436             :         Datum       aclDatum;
    2437             :         bool        isNull;
    2438             :         AclMode     avail_goptions;
    2439             :         AclMode     this_privileges;
    2440             :         Acl        *old_acl;
    2441             :         Acl        *new_acl;
    2442             :         Oid         grantorId;
    2443             :         Oid         ownerId;
    2444             :         HeapTuple   tuple;
    2445             :         int         noldmembers;
    2446             :         int         nnewmembers;
    2447             :         Oid        *oldmembers;
    2448             :         Oid        *newmembers;
    2449             : 
    2450         134 :         tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
    2451         134 :         if (!HeapTupleIsValid(tuple))
    2452           0 :             elog(ERROR, "cache lookup failed for parameter ACL %u",
    2453             :                  parameterId);
    2454             : 
    2455             :         /* We'll need the GUC's name */
    2456         134 :         nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
    2457             :                                            Anum_pg_parameter_acl_parname);
    2458         134 :         parname = TextDatumGetCString(nameDatum);
    2459             : 
    2460             :         /* Treat all parameters as belonging to the bootstrap superuser. */
    2461         134 :         ownerId = BOOTSTRAP_SUPERUSERID;
    2462             : 
    2463             :         /*
    2464             :          * Get working copy of existing ACL. If there's no ACL, substitute the
    2465             :          * proper default.
    2466             :          */
    2467         134 :         aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    2468             :                                    Anum_pg_parameter_acl_paracl,
    2469             :                                    &isNull);
    2470             : 
    2471         134 :         if (isNull)
    2472             :         {
    2473          66 :             old_acl = acldefault(istmt->objtype, ownerId);
    2474             :             /* There are no old member roles according to the catalogs */
    2475          66 :             noldmembers = 0;
    2476          66 :             oldmembers = NULL;
    2477             :         }
    2478             :         else
    2479             :         {
    2480          68 :             old_acl = DatumGetAclPCopy(aclDatum);
    2481             :             /* Get the roles mentioned in the existing ACL */
    2482          68 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2483             :         }
    2484             : 
    2485             :         /* Determine ID to do the grant as, and available grant options */
    2486         134 :         select_best_grantor(GetUserId(), istmt->privileges,
    2487             :                             old_acl, ownerId,
    2488             :                             &grantorId, &avail_goptions);
    2489             : 
    2490             :         /*
    2491             :          * Restrict the privileges to what we can actually grant, and emit the
    2492             :          * standards-mandated warning and error messages.
    2493             :          */
    2494             :         this_privileges =
    2495         134 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2496         134 :                                      istmt->all_privs, istmt->privileges,
    2497             :                                      parameterId, grantorId,
    2498             :                                      OBJECT_PARAMETER_ACL,
    2499             :                                      parname,
    2500             :                                      0, NULL);
    2501             : 
    2502             :         /*
    2503             :          * Generate new ACL.
    2504             :          */
    2505         134 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2506         134 :                                        istmt->grant_option, istmt->behavior,
    2507             :                                        istmt->grantees, this_privileges,
    2508             :                                        grantorId, ownerId);
    2509             : 
    2510             :         /*
    2511             :          * We need the members of both old and new ACLs so we can correct the
    2512             :          * shared dependency information.
    2513             :          */
    2514         134 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2515             : 
    2516             :         /*
    2517             :          * If the new ACL is equal to the default, we don't need the catalog
    2518             :          * entry any longer.  Delete it rather than updating it, to avoid
    2519             :          * leaving a degenerate entry.
    2520             :          */
    2521         134 :         if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
    2522             :         {
    2523          58 :             CatalogTupleDelete(relation, &tuple->t_self);
    2524             :         }
    2525             :         else
    2526             :         {
    2527             :             /* finished building new ACL value, now insert it */
    2528             :             HeapTuple   newtuple;
    2529          76 :             Datum       values[Natts_pg_parameter_acl] = {0};
    2530          76 :             bool        nulls[Natts_pg_parameter_acl] = {0};
    2531          76 :             bool        replaces[Natts_pg_parameter_acl] = {0};
    2532             : 
    2533          76 :             replaces[Anum_pg_parameter_acl_paracl - 1] = true;
    2534          76 :             values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
    2535             : 
    2536          76 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2537             :                                          values, nulls, replaces);
    2538             : 
    2539          76 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2540             :         }
    2541             : 
    2542             :         /* Update initial privileges for extensions */
    2543         134 :         recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
    2544             :                                 new_acl);
    2545             : 
    2546             :         /* Update the shared dependency ACL info */
    2547         134 :         updateAclDependencies(ParameterAclRelationId, parameterId, 0,
    2548             :                               ownerId,
    2549             :                               noldmembers, oldmembers,
    2550             :                               nnewmembers, newmembers);
    2551             : 
    2552         134 :         ReleaseSysCache(tuple);
    2553         134 :         pfree(new_acl);
    2554             : 
    2555             :         /* prevent error when processing duplicate objects */
    2556         134 :         CommandCounterIncrement();
    2557             :     }
    2558             : 
    2559          96 :     table_close(relation, RowExclusiveLock);
    2560          96 : }
    2561             : 
    2562             : 
    2563             : static AclMode
    2564       27130 : string_to_privilege(const char *privname)
    2565             : {
    2566       27130 :     if (strcmp(privname, "insert") == 0)
    2567         234 :         return ACL_INSERT;
    2568       26896 :     if (strcmp(privname, "select") == 0)
    2569       16556 :         return ACL_SELECT;
    2570       10340 :     if (strcmp(privname, "update") == 0)
    2571         372 :         return ACL_UPDATE;
    2572        9968 :     if (strcmp(privname, "delete") == 0)
    2573         120 :         return ACL_DELETE;
    2574        9848 :     if (strcmp(privname, "truncate") == 0)
    2575          34 :         return ACL_TRUNCATE;
    2576        9814 :     if (strcmp(privname, "references") == 0)
    2577          14 :         return ACL_REFERENCES;
    2578        9800 :     if (strcmp(privname, "trigger") == 0)
    2579           8 :         return ACL_TRIGGER;
    2580        9792 :     if (strcmp(privname, "execute") == 0)
    2581        8464 :         return ACL_EXECUTE;
    2582        1328 :     if (strcmp(privname, "usage") == 0)
    2583         690 :         return ACL_USAGE;
    2584         638 :     if (strcmp(privname, "create") == 0)
    2585         290 :         return ACL_CREATE;
    2586         348 :     if (strcmp(privname, "temporary") == 0)
    2587         208 :         return ACL_CREATE_TEMP;
    2588         140 :     if (strcmp(privname, "temp") == 0)
    2589           2 :         return ACL_CREATE_TEMP;
    2590         138 :     if (strcmp(privname, "connect") == 0)
    2591          34 :         return ACL_CONNECT;
    2592         104 :     if (strcmp(privname, "set") == 0)
    2593          48 :         return ACL_SET;
    2594          56 :     if (strcmp(privname, "alter system") == 0)
    2595          24 :         return ACL_ALTER_SYSTEM;
    2596          32 :     if (strcmp(privname, "maintain") == 0)
    2597          32 :         return ACL_MAINTAIN;
    2598           0 :     ereport(ERROR,
    2599             :             (errcode(ERRCODE_SYNTAX_ERROR),
    2600             :              errmsg("unrecognized privilege type \"%s\"", privname)));
    2601             :     return 0;                   /* appease compiler */
    2602             : }
    2603             : 
    2604             : static const char *
    2605          24 : privilege_to_string(AclMode privilege)
    2606             : {
    2607          24 :     switch (privilege)
    2608             :     {
    2609           6 :         case ACL_INSERT:
    2610           6 :             return "INSERT";
    2611           0 :         case ACL_SELECT:
    2612           0 :             return "SELECT";
    2613           0 :         case ACL_UPDATE:
    2614           0 :             return "UPDATE";
    2615           0 :         case ACL_DELETE:
    2616           0 :             return "DELETE";
    2617           0 :         case ACL_TRUNCATE:
    2618           0 :             return "TRUNCATE";
    2619           0 :         case ACL_REFERENCES:
    2620           0 :             return "REFERENCES";
    2621           0 :         case ACL_TRIGGER:
    2622           0 :             return "TRIGGER";
    2623           0 :         case ACL_EXECUTE:
    2624           0 :             return "EXECUTE";
    2625          18 :         case ACL_USAGE:
    2626          18 :             return "USAGE";
    2627           0 :         case ACL_CREATE:
    2628           0 :             return "CREATE";
    2629           0 :         case ACL_CREATE_TEMP:
    2630           0 :             return "TEMP";
    2631           0 :         case ACL_CONNECT:
    2632           0 :             return "CONNECT";
    2633           0 :         case ACL_SET:
    2634           0 :             return "SET";
    2635           0 :         case ACL_ALTER_SYSTEM:
    2636           0 :             return "ALTER SYSTEM";
    2637           0 :         case ACL_MAINTAIN:
    2638           0 :             return "MAINTAIN";
    2639           0 :         default:
    2640           0 :             elog(ERROR, "unrecognized privilege: %d", (int) privilege);
    2641             :     }
    2642             :     return NULL;                /* appease compiler */
    2643             : }
    2644             : 
    2645             : /*
    2646             :  * Standardized reporting of aclcheck permissions failures.
    2647             :  *
    2648             :  * Note: we do not double-quote the %s's below, because many callers
    2649             :  * supply strings that might be already quoted.
    2650             :  */
    2651             : void
    2652        2710 : aclcheck_error(AclResult aclerr, ObjectType objtype,
    2653             :                const char *objectname)
    2654             : {
    2655        2710 :     switch (aclerr)
    2656             :     {
    2657           0 :         case ACLCHECK_OK:
    2658             :             /* no error, so return to caller */
    2659           0 :             break;
    2660        2196 :         case ACLCHECK_NO_PRIV:
    2661             :             {
    2662        2196 :                 const char *msg = "???";
    2663             : 
    2664             :                 switch (objtype)
    2665             :                 {
    2666           6 :                     case OBJECT_AGGREGATE:
    2667           6 :                         msg = gettext_noop("permission denied for aggregate %s");
    2668           6 :                         break;
    2669           0 :                     case OBJECT_COLLATION:
    2670           0 :                         msg = gettext_noop("permission denied for collation %s");
    2671           0 :                         break;
    2672           0 :                     case OBJECT_COLUMN:
    2673           0 :                         msg = gettext_noop("permission denied for column %s");
    2674           0 :                         break;
    2675           0 :                     case OBJECT_CONVERSION:
    2676           0 :                         msg = gettext_noop("permission denied for conversion %s");
    2677           0 :                         break;
    2678          18 :                     case OBJECT_DATABASE:
    2679          18 :                         msg = gettext_noop("permission denied for database %s");
    2680          18 :                         break;
    2681           0 :                     case OBJECT_DOMAIN:
    2682           0 :                         msg = gettext_noop("permission denied for domain %s");
    2683           0 :                         break;
    2684           0 :                     case OBJECT_EVENT_TRIGGER:
    2685           0 :                         msg = gettext_noop("permission denied for event trigger %s");
    2686           0 :                         break;
    2687           0 :                     case OBJECT_EXTENSION:
    2688           0 :                         msg = gettext_noop("permission denied for extension %s");
    2689           0 :                         break;
    2690          44 :                     case OBJECT_FDW:
    2691          44 :                         msg = gettext_noop("permission denied for foreign-data wrapper %s");
    2692          44 :                         break;
    2693          20 :                     case OBJECT_FOREIGN_SERVER:
    2694          20 :                         msg = gettext_noop("permission denied for foreign server %s");
    2695          20 :                         break;
    2696           2 :                     case OBJECT_FOREIGN_TABLE:
    2697           2 :                         msg = gettext_noop("permission denied for foreign table %s");
    2698           2 :                         break;
    2699         102 :                     case OBJECT_FUNCTION:
    2700         102 :                         msg = gettext_noop("permission denied for function %s");
    2701         102 :                         break;
    2702          12 :                     case OBJECT_INDEX:
    2703          12 :                         msg = gettext_noop("permission denied for index %s");
    2704          12 :                         break;
    2705           8 :                     case OBJECT_LANGUAGE:
    2706           8 :                         msg = gettext_noop("permission denied for language %s");
    2707           8 :                         break;
    2708           0 :                     case OBJECT_LARGEOBJECT:
    2709           0 :                         msg = gettext_noop("permission denied for large object %s");
    2710           0 :                         break;
    2711           6 :                     case OBJECT_MATVIEW:
    2712           6 :                         msg = gettext_noop("permission denied for materialized view %s");
    2713           6 :                         break;
    2714           0 :                     case OBJECT_OPCLASS:
    2715           0 :                         msg = gettext_noop("permission denied for operator class %s");
    2716           0 :                         break;
    2717           0 :                     case OBJECT_OPERATOR:
    2718           0 :                         msg = gettext_noop("permission denied for operator %s");
    2719           0 :                         break;
    2720           0 :                     case OBJECT_OPFAMILY:
    2721           0 :                         msg = gettext_noop("permission denied for operator family %s");
    2722           0 :                         break;
    2723           0 :                     case OBJECT_PARAMETER_ACL:
    2724           0 :                         msg = gettext_noop("permission denied for parameter %s");
    2725           0 :                         break;
    2726           0 :                     case OBJECT_POLICY:
    2727           0 :                         msg = gettext_noop("permission denied for policy %s");
    2728           0 :                         break;
    2729          12 :                     case OBJECT_PROCEDURE:
    2730          12 :                         msg = gettext_noop("permission denied for procedure %s");
    2731          12 :                         break;
    2732           0 :                     case OBJECT_PUBLICATION:
    2733           0 :                         msg = gettext_noop("permission denied for publication %s");
    2734           0 :                         break;
    2735           0 :                     case OBJECT_ROUTINE:
    2736           0 :                         msg = gettext_noop("permission denied for routine %s");
    2737           0 :                         break;
    2738          14 :                     case OBJECT_SCHEMA:
    2739          14 :                         msg = gettext_noop("permission denied for schema %s");
    2740          14 :                         break;
    2741           0 :                     case OBJECT_SEQUENCE:
    2742           0 :                         msg = gettext_noop("permission denied for sequence %s");
    2743           0 :                         break;
    2744           0 :                     case OBJECT_STATISTIC_EXT:
    2745           0 :                         msg = gettext_noop("permission denied for statistics object %s");
    2746           0 :                         break;
    2747           0 :                     case OBJECT_SUBSCRIPTION:
    2748           0 :                         msg = gettext_noop("permission denied for subscription %s");
    2749           0 :                         break;
    2750        1410 :                     case OBJECT_TABLE:
    2751        1410 :                         msg = gettext_noop("permission denied for table %s");
    2752        1410 :                         break;
    2753          18 :                     case OBJECT_TABLESPACE:
    2754          18 :                         msg = gettext_noop("permission denied for tablespace %s");
    2755          18 :                         break;
    2756           0 :                     case OBJECT_TSCONFIGURATION:
    2757           0 :                         msg = gettext_noop("permission denied for text search configuration %s");
    2758           0 :                         break;
    2759           0 :                     case OBJECT_TSDICTIONARY:
    2760           0 :                         msg = gettext_noop("permission denied for text search dictionary %s");
    2761           0 :                         break;
    2762         120 :                     case OBJECT_TYPE:
    2763         120 :                         msg = gettext_noop("permission denied for type %s");
    2764         120 :                         break;
    2765         404 :                     case OBJECT_VIEW:
    2766         404 :                         msg = gettext_noop("permission denied for view %s");
    2767         404 :                         break;
    2768             :                         /* these currently aren't used */
    2769           0 :                     case OBJECT_ACCESS_METHOD:
    2770             :                     case OBJECT_AMOP:
    2771             :                     case OBJECT_AMPROC:
    2772             :                     case OBJECT_ATTRIBUTE:
    2773             :                     case OBJECT_CAST:
    2774             :                     case OBJECT_DEFAULT:
    2775             :                     case OBJECT_DEFACL:
    2776             :                     case OBJECT_DOMCONSTRAINT:
    2777             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2778             :                     case OBJECT_PUBLICATION_REL:
    2779             :                     case OBJECT_ROLE:
    2780             :                     case OBJECT_RULE:
    2781             :                     case OBJECT_TABCONSTRAINT:
    2782             :                     case OBJECT_TRANSFORM:
    2783             :                     case OBJECT_TRIGGER:
    2784             :                     case OBJECT_TSPARSER:
    2785             :                     case OBJECT_TSTEMPLATE:
    2786             :                     case OBJECT_USER_MAPPING:
    2787           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2788             :                 }
    2789             : 
    2790        2196 :                 ereport(ERROR,
    2791             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2792             :                          errmsg(msg, objectname)));
    2793             :                 break;
    2794             :             }
    2795         514 :         case ACLCHECK_NOT_OWNER:
    2796             :             {
    2797         514 :                 const char *msg = "???";
    2798             : 
    2799             :                 switch (objtype)
    2800             :                 {
    2801           6 :                     case OBJECT_AGGREGATE:
    2802           6 :                         msg = gettext_noop("must be owner of aggregate %s");
    2803           6 :                         break;
    2804           0 :                     case OBJECT_COLLATION:
    2805           0 :                         msg = gettext_noop("must be owner of collation %s");
    2806           0 :                         break;
    2807          18 :                     case OBJECT_CONVERSION:
    2808          18 :                         msg = gettext_noop("must be owner of conversion %s");
    2809          18 :                         break;
    2810           0 :                     case OBJECT_DATABASE:
    2811           0 :                         msg = gettext_noop("must be owner of database %s");
    2812           0 :                         break;
    2813           0 :                     case OBJECT_DOMAIN:
    2814           0 :                         msg = gettext_noop("must be owner of domain %s");
    2815           0 :                         break;
    2816           0 :                     case OBJECT_EVENT_TRIGGER:
    2817           0 :                         msg = gettext_noop("must be owner of event trigger %s");
    2818           0 :                         break;
    2819           0 :                     case OBJECT_EXTENSION:
    2820           0 :                         msg = gettext_noop("must be owner of extension %s");
    2821           0 :                         break;
    2822          18 :                     case OBJECT_FDW:
    2823          18 :                         msg = gettext_noop("must be owner of foreign-data wrapper %s");
    2824          18 :                         break;
    2825         114 :                     case OBJECT_FOREIGN_SERVER:
    2826         114 :                         msg = gettext_noop("must be owner of foreign server %s");
    2827         114 :                         break;
    2828           0 :                     case OBJECT_FOREIGN_TABLE:
    2829           0 :                         msg = gettext_noop("must be owner of foreign table %s");
    2830           0 :                         break;
    2831          42 :                     case OBJECT_FUNCTION:
    2832          42 :                         msg = gettext_noop("must be owner of function %s");
    2833          42 :                         break;
    2834          24 :                     case OBJECT_INDEX:
    2835          24 :                         msg = gettext_noop("must be owner of index %s");
    2836          24 :                         break;
    2837          12 :                     case OBJECT_LANGUAGE:
    2838          12 :                         msg = gettext_noop("must be owner of language %s");
    2839          12 :                         break;
    2840           0 :                     case OBJECT_LARGEOBJECT:
    2841           0 :                         msg = gettext_noop("must be owner of large object %s");
    2842           0 :                         break;
    2843           0 :                     case OBJECT_MATVIEW:
    2844           0 :                         msg = gettext_noop("must be owner of materialized view %s");
    2845           0 :                         break;
    2846          18 :                     case OBJECT_OPCLASS:
    2847          18 :                         msg = gettext_noop("must be owner of operator class %s");
    2848          18 :                         break;
    2849          18 :                     case OBJECT_OPERATOR:
    2850          18 :                         msg = gettext_noop("must be owner of operator %s");
    2851          18 :                         break;
    2852          18 :                     case OBJECT_OPFAMILY:
    2853          18 :                         msg = gettext_noop("must be owner of operator family %s");
    2854          18 :                         break;
    2855           6 :                     case OBJECT_PROCEDURE:
    2856           6 :                         msg = gettext_noop("must be owner of procedure %s");
    2857           6 :                         break;
    2858           6 :                     case OBJECT_PUBLICATION:
    2859           6 :                         msg = gettext_noop("must be owner of publication %s");
    2860           6 :                         break;
    2861           0 :                     case OBJECT_ROUTINE:
    2862           0 :                         msg = gettext_noop("must be owner of routine %s");
    2863           0 :                         break;
    2864           6 :                     case OBJECT_SEQUENCE:
    2865           6 :                         msg = gettext_noop("must be owner of sequence %s");
    2866           6 :                         break;
    2867           6 :                     case OBJECT_SUBSCRIPTION:
    2868           6 :                         msg = gettext_noop("must be owner of subscription %s");
    2869           6 :                         break;
    2870          70 :                     case OBJECT_TABLE:
    2871          70 :                         msg = gettext_noop("must be owner of table %s");
    2872          70 :                         break;
    2873           6 :                     case OBJECT_TYPE:
    2874           6 :                         msg = gettext_noop("must be owner of type %s");
    2875           6 :                         break;
    2876          18 :                     case OBJECT_VIEW:
    2877          18 :                         msg = gettext_noop("must be owner of view %s");
    2878          18 :                         break;
    2879          18 :                     case OBJECT_SCHEMA:
    2880          18 :                         msg = gettext_noop("must be owner of schema %s");
    2881          18 :                         break;
    2882          36 :                     case OBJECT_STATISTIC_EXT:
    2883          36 :                         msg = gettext_noop("must be owner of statistics object %s");
    2884          36 :                         break;
    2885           0 :                     case OBJECT_TABLESPACE:
    2886           0 :                         msg = gettext_noop("must be owner of tablespace %s");
    2887           0 :                         break;
    2888          18 :                     case OBJECT_TSCONFIGURATION:
    2889          18 :                         msg = gettext_noop("must be owner of text search configuration %s");
    2890          18 :                         break;
    2891          18 :                     case OBJECT_TSDICTIONARY:
    2892          18 :                         msg = gettext_noop("must be owner of text search dictionary %s");
    2893          18 :                         break;
    2894             : 
    2895             :                         /*
    2896             :                          * Special cases: For these, the error message talks
    2897             :                          * about "relation", because that's where the
    2898             :                          * ownership is attached.  See also
    2899             :                          * check_object_ownership().
    2900             :                          */
    2901          18 :                     case OBJECT_COLUMN:
    2902             :                     case OBJECT_POLICY:
    2903             :                     case OBJECT_RULE:
    2904             :                     case OBJECT_TABCONSTRAINT:
    2905             :                     case OBJECT_TRIGGER:
    2906          18 :                         msg = gettext_noop("must be owner of relation %s");
    2907          18 :                         break;
    2908             :                         /* these currently aren't used */
    2909           0 :                     case OBJECT_ACCESS_METHOD:
    2910             :                     case OBJECT_AMOP:
    2911             :                     case OBJECT_AMPROC:
    2912             :                     case OBJECT_ATTRIBUTE:
    2913             :                     case OBJECT_CAST:
    2914             :                     case OBJECT_DEFAULT:
    2915             :                     case OBJECT_DEFACL:
    2916             :                     case OBJECT_DOMCONSTRAINT:
    2917             :                     case OBJECT_PARAMETER_ACL:
    2918             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2919             :                     case OBJECT_PUBLICATION_REL:
    2920             :                     case OBJECT_ROLE:
    2921             :                     case OBJECT_TRANSFORM:
    2922             :                     case OBJECT_TSPARSER:
    2923             :                     case OBJECT_TSTEMPLATE:
    2924             :                     case OBJECT_USER_MAPPING:
    2925           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2926             :                 }
    2927             : 
    2928         514 :                 ereport(ERROR,
    2929             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2930             :                          errmsg(msg, objectname)));
    2931             :                 break;
    2932             :             }
    2933           0 :         default:
    2934           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    2935             :             break;
    2936             :     }
    2937           0 : }
    2938             : 
    2939             : 
    2940             : void
    2941           0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
    2942             :                    const char *objectname, const char *colname)
    2943             : {
    2944           0 :     switch (aclerr)
    2945             :     {
    2946           0 :         case ACLCHECK_OK:
    2947             :             /* no error, so return to caller */
    2948           0 :             break;
    2949           0 :         case ACLCHECK_NO_PRIV:
    2950           0 :             ereport(ERROR,
    2951             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2952             :                      errmsg("permission denied for column \"%s\" of relation \"%s\"",
    2953             :                             colname, objectname)));
    2954             :             break;
    2955           0 :         case ACLCHECK_NOT_OWNER:
    2956             :             /* relation msg is OK since columns don't have separate owners */
    2957           0 :             aclcheck_error(aclerr, objtype, objectname);
    2958           0 :             break;
    2959           0 :         default:
    2960           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    2961             :             break;
    2962             :     }
    2963           0 : }
    2964             : 
    2965             : 
    2966             : /*
    2967             :  * Special common handling for types: use element type instead of array type,
    2968             :  * and format nicely
    2969             :  */
    2970             : void
    2971         120 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
    2972             : {
    2973         120 :     Oid         element_type = get_element_type(typeOid);
    2974             : 
    2975         120 :     aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
    2976           0 : }
    2977             : 
    2978             : 
    2979             : /*
    2980             :  * Relay for the various pg_*_mask routines depending on object kind
    2981             :  */
    2982             : static AclMode
    2983          72 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
    2984             :            AclMode mask, AclMaskHow how)
    2985             : {
    2986          72 :     switch (objtype)
    2987             :     {
    2988           0 :         case OBJECT_COLUMN:
    2989             :             return
    2990           0 :                 pg_class_aclmask(object_oid, roleid, mask, how) |
    2991           0 :                 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
    2992          18 :         case OBJECT_TABLE:
    2993             :         case OBJECT_SEQUENCE:
    2994          18 :             return pg_class_aclmask(object_oid, roleid, mask, how);
    2995           0 :         case OBJECT_DATABASE:
    2996           0 :             return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
    2997           0 :         case OBJECT_FUNCTION:
    2998           0 :             return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
    2999           6 :         case OBJECT_LANGUAGE:
    3000           6 :             return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
    3001           0 :         case OBJECT_LARGEOBJECT:
    3002           0 :             return pg_largeobject_aclmask_snapshot(object_oid, roleid,
    3003             :                                                    mask, how, NULL);
    3004           0 :         case OBJECT_PARAMETER_ACL:
    3005           0 :             return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
    3006           0 :         case OBJECT_SCHEMA:
    3007           0 :             return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
    3008           0 :         case OBJECT_STATISTIC_EXT:
    3009           0 :             elog(ERROR, "grantable rights not supported for statistics objects");
    3010             :             /* not reached, but keep compiler quiet */
    3011             :             return ACL_NO_RIGHTS;
    3012           0 :         case OBJECT_TABLESPACE:
    3013           0 :             return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
    3014          18 :         case OBJECT_FDW:
    3015          18 :             return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
    3016          18 :         case OBJECT_FOREIGN_SERVER:
    3017          18 :             return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
    3018           0 :         case OBJECT_EVENT_TRIGGER:
    3019           0 :             elog(ERROR, "grantable rights not supported for event triggers");
    3020             :             /* not reached, but keep compiler quiet */
    3021             :             return ACL_NO_RIGHTS;
    3022          12 :         case OBJECT_TYPE:
    3023          12 :             return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
    3024           0 :         default:
    3025           0 :             elog(ERROR, "unrecognized object type: %d",
    3026             :                  (int) objtype);
    3027             :             /* not reached, but keep compiler quiet */
    3028             :             return ACL_NO_RIGHTS;
    3029             :     }
    3030             : }
    3031             : 
    3032             : 
    3033             : /* ****************************************************************
    3034             :  * Exported routines for examining a user's privileges for various objects
    3035             :  *
    3036             :  * See aclmask() for a description of the common API for these functions.
    3037             :  * ****************************************************************
    3038             :  */
    3039             : 
    3040             : /*
    3041             :  * Generic routine for examining a user's privileges for an object
    3042             :  */
    3043             : static AclMode
    3044          54 : object_aclmask(Oid classid, Oid objectid, Oid roleid,
    3045             :                AclMode mask, AclMaskHow how)
    3046             : {
    3047          54 :     return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
    3048             : }
    3049             : 
    3050             : /*
    3051             :  * Generic routine for examining a user's privileges for an object,
    3052             :  * with is_missing
    3053             :  */
    3054             : static AclMode
    3055     3171916 : object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
    3056             :                    AclMode mask, AclMaskHow how,
    3057             :                    bool *is_missing)
    3058             : {
    3059             :     int         cacheid;
    3060             :     AclMode     result;
    3061             :     HeapTuple   tuple;
    3062             :     Datum       aclDatum;
    3063             :     bool        isNull;
    3064             :     Acl        *acl;
    3065             :     Oid         ownerId;
    3066             : 
    3067             :     /* Special cases */
    3068     3171916 :     switch (classid)
    3069             :     {
    3070      961100 :         case NamespaceRelationId:
    3071      961100 :             return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
    3072             :                                             is_missing);
    3073      347782 :         case TypeRelationId:
    3074      347782 :             return pg_type_aclmask_ext(objectid, roleid, mask, how,
    3075             :                                        is_missing);
    3076             :     }
    3077             : 
    3078             :     /* Even more special cases */
    3079             :     Assert(classid != RelationRelationId);  /* should use pg_class_acl* */
    3080             :     Assert(classid != LargeObjectMetadataRelationId);   /* should use
    3081             :                                                          * pg_largeobject_acl* */
    3082             : 
    3083             :     /* Superusers bypass all permission checking. */
    3084     1863034 :     if (superuser_arg(roleid))
    3085     1821284 :         return mask;
    3086             : 
    3087             :     /*
    3088             :      * Get the object's ACL from its catalog
    3089             :      */
    3090             : 
    3091       41750 :     cacheid = get_object_catcache_oid(classid);
    3092             : 
    3093       41750 :     tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    3094       41750 :     if (!HeapTupleIsValid(tuple))
    3095             :     {
    3096           0 :         if (is_missing != NULL)
    3097             :         {
    3098             :             /* return "no privileges" instead of throwing an error */
    3099           0 :             *is_missing = true;
    3100           0 :             return 0;
    3101             :         }
    3102             :         else
    3103           0 :             elog(ERROR, "cache lookup failed for %s %u",
    3104             :                  get_object_class_descr(classid), objectid);
    3105             :     }
    3106             : 
    3107       41750 :     ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    3108             :                                                       tuple,
    3109       41750 :                                                       get_object_attnum_owner(classid)));
    3110             : 
    3111       41750 :     aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
    3112             :                                &isNull);
    3113       41750 :     if (isNull)
    3114             :     {
    3115             :         /* No ACL, so build default ACL */
    3116       39142 :         acl = acldefault(get_object_type(classid, objectid), ownerId);
    3117       39142 :         aclDatum = (Datum) 0;
    3118             :     }
    3119             :     else
    3120             :     {
    3121             :         /* detoast ACL if necessary */
    3122        2608 :         acl = DatumGetAclP(aclDatum);
    3123             :     }
    3124             : 
    3125       41750 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3126             : 
    3127             :     /* if we have a detoasted copy, free it */
    3128       41750 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3129       41750 :         pfree(acl);
    3130             : 
    3131       41750 :     ReleaseSysCache(tuple);
    3132             : 
    3133       41750 :     return result;
    3134             : }
    3135             : 
    3136             : /*
    3137             :  * Routine for examining a user's privileges for a column
    3138             :  *
    3139             :  * Note: this considers only privileges granted specifically on the column.
    3140             :  * It is caller's responsibility to take relation-level privileges into account
    3141             :  * as appropriate.  (For the same reason, we have no special case for
    3142             :  * superuser-ness here.)
    3143             :  */
    3144             : static AclMode
    3145           0 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
    3146             :                      AclMode mask, AclMaskHow how)
    3147             : {
    3148           0 :     return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
    3149             :                                     mask, how, NULL);
    3150             : }
    3151             : 
    3152             : /*
    3153             :  * Routine for examining a user's privileges for a column, with is_missing
    3154             :  */
    3155             : static AclMode
    3156        7798 : pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
    3157             :                          AclMode mask, AclMaskHow how, bool *is_missing)
    3158             : {
    3159             :     AclMode     result;
    3160             :     HeapTuple   classTuple;
    3161             :     HeapTuple   attTuple;
    3162             :     Form_pg_class classForm;
    3163             :     Form_pg_attribute attributeForm;
    3164             :     Datum       aclDatum;
    3165             :     bool        isNull;
    3166             :     Acl        *acl;
    3167             :     Oid         ownerId;
    3168             : 
    3169             :     /*
    3170             :      * First, get the column's ACL from its pg_attribute entry
    3171             :      */
    3172        7798 :     attTuple = SearchSysCache2(ATTNUM,
    3173             :                                ObjectIdGetDatum(table_oid),
    3174             :                                Int16GetDatum(attnum));
    3175        7798 :     if (!HeapTupleIsValid(attTuple))
    3176             :     {
    3177          30 :         if (is_missing != NULL)
    3178             :         {
    3179             :             /* return "no privileges" instead of throwing an error */
    3180          30 :             *is_missing = true;
    3181          30 :             return 0;
    3182             :         }
    3183             :         else
    3184           0 :             ereport(ERROR,
    3185             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    3186             :                      errmsg("attribute %d of relation with OID %u does not exist",
    3187             :                             attnum, table_oid)));
    3188             :     }
    3189             : 
    3190        7768 :     attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
    3191             : 
    3192             :     /* Check dropped columns, too */
    3193        7768 :     if (attributeForm->attisdropped)
    3194             :     {
    3195          12 :         if (is_missing != NULL)
    3196             :         {
    3197             :             /* return "no privileges" instead of throwing an error */
    3198          12 :             *is_missing = true;
    3199          12 :             ReleaseSysCache(attTuple);
    3200          12 :             return 0;
    3201             :         }
    3202             :         else
    3203           0 :             ereport(ERROR,
    3204             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    3205             :                      errmsg("attribute %d of relation with OID %u does not exist",
    3206             :                             attnum, table_oid)));
    3207             :     }
    3208             : 
    3209        7756 :     aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
    3210             :                                &isNull);
    3211             : 
    3212             :     /*
    3213             :      * Here we hard-wire knowledge that the default ACL for a column grants no
    3214             :      * privileges, so that we can fall out quickly in the very common case
    3215             :      * where attacl is null.
    3216             :      */
    3217        7756 :     if (isNull)
    3218             :     {
    3219        4926 :         ReleaseSysCache(attTuple);
    3220        4926 :         return 0;
    3221             :     }
    3222             : 
    3223             :     /*
    3224             :      * Must get the relation's ownerId from pg_class.  Since we already found
    3225             :      * a pg_attribute entry, the only likely reason for this to fail is that a
    3226             :      * concurrent DROP of the relation committed since then (which could only
    3227             :      * happen if we don't have lock on the relation).  Treat that similarly to
    3228             :      * not finding the attribute entry.
    3229             :      */
    3230        2830 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3231        2830 :     if (!HeapTupleIsValid(classTuple))
    3232             :     {
    3233           0 :         ReleaseSysCache(attTuple);
    3234           0 :         if (is_missing != NULL)
    3235             :         {
    3236             :             /* return "no privileges" instead of throwing an error */
    3237           0 :             *is_missing = true;
    3238           0 :             return 0;
    3239             :         }
    3240             :         else
    3241           0 :             ereport(ERROR,
    3242             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3243             :                      errmsg("relation with OID %u does not exist",
    3244             :                             table_oid)));
    3245             :     }
    3246        2830 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3247             : 
    3248        2830 :     ownerId = classForm->relowner;
    3249             : 
    3250        2830 :     ReleaseSysCache(classTuple);
    3251             : 
    3252             :     /* detoast column's ACL if necessary */
    3253        2830 :     acl = DatumGetAclP(aclDatum);
    3254             : 
    3255        2830 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3256             : 
    3257             :     /* if we have a detoasted copy, free it */
    3258        2830 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3259        2830 :         pfree(acl);
    3260             : 
    3261        2830 :     ReleaseSysCache(attTuple);
    3262             : 
    3263        2830 :     return result;
    3264             : }
    3265             : 
    3266             : /*
    3267             :  * Exported routine for examining a user's privileges for a table
    3268             :  */
    3269             : AclMode
    3270      574084 : pg_class_aclmask(Oid table_oid, Oid roleid,
    3271             :                  AclMode mask, AclMaskHow how)
    3272             : {
    3273      574084 :     return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
    3274             : }
    3275             : 
    3276             : /*
    3277             :  * Routine for examining a user's privileges for a table, with is_missing
    3278             :  */
    3279             : static AclMode
    3280     2945782 : pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
    3281             :                      AclMaskHow how, bool *is_missing)
    3282             : {
    3283             :     AclMode     result;
    3284             :     HeapTuple   tuple;
    3285             :     Form_pg_class classForm;
    3286             :     Datum       aclDatum;
    3287             :     bool        isNull;
    3288             :     Acl        *acl;
    3289             :     Oid         ownerId;
    3290             : 
    3291             :     /*
    3292             :      * Must get the relation's tuple from pg_class
    3293             :      */
    3294     2945782 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3295     2945782 :     if (!HeapTupleIsValid(tuple))
    3296             :     {
    3297           8 :         if (is_missing != NULL)
    3298             :         {
    3299             :             /* return "no privileges" instead of throwing an error */
    3300           8 :             *is_missing = true;
    3301           8 :             return 0;
    3302             :         }
    3303             :         else
    3304           0 :             ereport(ERROR,
    3305             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3306             :                      errmsg("relation with OID %u does not exist",
    3307             :                             table_oid)));
    3308             :     }
    3309             : 
    3310     2945774 :     classForm = (Form_pg_class) GETSTRUCT(tuple);
    3311             : 
    3312             :     /*
    3313             :      * Deny anyone permission to update a system catalog unless
    3314             :      * pg_authid.rolsuper is set.
    3315             :      *
    3316             :      * As of 7.4 we have some updatable system views; those shouldn't be
    3317             :      * protected in this way.  Assume the view rules can take care of
    3318             :      * themselves.  ACL_USAGE is if we ever have system sequences.
    3319             :      */
    3320     3779352 :     if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
    3321      833578 :         IsSystemClass(table_oid, classForm) &&
    3322        5116 :         classForm->relkind != RELKIND_VIEW &&
    3323        5116 :         !superuser_arg(roleid))
    3324          70 :         mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
    3325             : 
    3326             :     /*
    3327             :      * Otherwise, superusers bypass all permission-checking.
    3328             :      */
    3329     2945774 :     if (superuser_arg(roleid))
    3330             :     {
    3331     2904974 :         ReleaseSysCache(tuple);
    3332     2904974 :         return mask;
    3333             :     }
    3334             : 
    3335             :     /*
    3336             :      * Normal case: get the relation's ACL from pg_class
    3337             :      */
    3338       40800 :     ownerId = classForm->relowner;
    3339             : 
    3340       40800 :     aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    3341             :                                &isNull);
    3342       40800 :     if (isNull)
    3343             :     {
    3344             :         /* No ACL, so build default ACL */
    3345        9084 :         switch (classForm->relkind)
    3346             :         {
    3347          48 :             case RELKIND_SEQUENCE:
    3348          48 :                 acl = acldefault(OBJECT_SEQUENCE, ownerId);
    3349          48 :                 break;
    3350        9036 :             default:
    3351        9036 :                 acl = acldefault(OBJECT_TABLE, ownerId);
    3352        9036 :                 break;
    3353             :         }
    3354        9084 :         aclDatum = (Datum) 0;
    3355             :     }
    3356             :     else
    3357             :     {
    3358             :         /* detoast rel's ACL if necessary */
    3359       31716 :         acl = DatumGetAclP(aclDatum);
    3360             :     }
    3361             : 
    3362       40800 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3363             : 
    3364             :     /* if we have a detoasted copy, free it */
    3365       40800 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3366       40800 :         pfree(acl);
    3367             : 
    3368       40800 :     ReleaseSysCache(tuple);
    3369             : 
    3370             :     /*
    3371             :      * Check if ACL_SELECT is being checked and, if so, and not set already as
    3372             :      * part of the result, then check if the user is a member of the
    3373             :      * pg_read_all_data role, which allows read access to all relations.
    3374             :      */
    3375       43042 :     if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
    3376        2242 :         has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
    3377          12 :         result |= ACL_SELECT;
    3378             : 
    3379             :     /*
    3380             :      * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
    3381             :      * so, and not set already as part of the result, then check if the user
    3382             :      * is a member of the pg_write_all_data role, which allows
    3383             :      * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
    3384             :      * which requires superuser, see above).
    3385             :      */
    3386       40800 :     if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
    3387        8566 :         !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
    3388        1926 :         has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
    3389          18 :         result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
    3390             : 
    3391             :     /*
    3392             :      * Check if ACL_MAINTAIN is being checked and, if so, and not already set
    3393             :      * as part of the result, then check if the user is a member of the
    3394             :      * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
    3395             :      * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
    3396             :      */
    3397       40800 :     if (mask & ACL_MAINTAIN &&
    3398        7432 :         !(result & ACL_MAINTAIN) &&
    3399        3426 :         has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
    3400          66 :         result |= ACL_MAINTAIN;
    3401             : 
    3402       40800 :     return result;
    3403             : }
    3404             : 
    3405             : /*
    3406             :  * Routine for examining a user's privileges for a configuration
    3407             :  * parameter (GUC), identified by GUC name.
    3408             :  */
    3409             : static AclMode
    3410         160 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
    3411             : {
    3412             :     AclMode     result;
    3413             :     char       *parname;
    3414             :     text       *partext;
    3415             :     HeapTuple   tuple;
    3416             : 
    3417             :     /* Superusers bypass all permission checking. */
    3418         160 :     if (superuser_arg(roleid))
    3419           2 :         return mask;
    3420             : 
    3421             :     /* Convert name to the form it should have in pg_parameter_acl... */
    3422         158 :     parname = convert_GUC_name_for_parameter_acl(name);
    3423         158 :     partext = cstring_to_text(parname);
    3424             : 
    3425             :     /* ... and look it up */
    3426         158 :     tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
    3427             : 
    3428         158 :     if (!HeapTupleIsValid(tuple))
    3429             :     {
    3430             :         /* If no entry, GUC has no permissions for non-superusers */
    3431          70 :         result = ACL_NO_RIGHTS;
    3432             :     }
    3433             :     else
    3434             :     {
    3435             :         Datum       aclDatum;
    3436             :         bool        isNull;
    3437             :         Acl        *acl;
    3438             : 
    3439          88 :         aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
    3440             :                                    Anum_pg_parameter_acl_paracl,
    3441             :                                    &isNull);
    3442          88 :         if (isNull)
    3443             :         {
    3444             :             /* No ACL, so build default ACL */
    3445           0 :             acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3446           0 :             aclDatum = (Datum) 0;
    3447             :         }
    3448             :         else
    3449             :         {
    3450             :             /* detoast ACL if necessary */
    3451          88 :             acl = DatumGetAclP(aclDatum);
    3452             :         }
    3453             : 
    3454          88 :         result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3455             : 
    3456             :         /* if we have a detoasted copy, free it */
    3457          88 :         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3458          88 :             pfree(acl);
    3459             : 
    3460          88 :         ReleaseSysCache(tuple);
    3461             :     }
    3462             : 
    3463         158 :     pfree(parname);
    3464         158 :     pfree(partext);
    3465             : 
    3466         158 :     return result;
    3467             : }
    3468             : 
    3469             : /*
    3470             :  * Routine for examining a user's privileges for a configuration
    3471             :  * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
    3472             :  */
    3473             : static AclMode
    3474           0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
    3475             : {
    3476             :     AclMode     result;
    3477             :     HeapTuple   tuple;
    3478             :     Datum       aclDatum;
    3479             :     bool        isNull;
    3480             :     Acl        *acl;
    3481             : 
    3482             :     /* Superusers bypass all permission checking. */
    3483           0 :     if (superuser_arg(roleid))
    3484           0 :         return mask;
    3485             : 
    3486             :     /* Get the ACL from pg_parameter_acl */
    3487           0 :     tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
    3488           0 :     if (!HeapTupleIsValid(tuple))
    3489           0 :         ereport(ERROR,
    3490             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3491             :                  errmsg("parameter ACL with OID %u does not exist",
    3492             :                         acl_oid)));
    3493             : 
    3494           0 :     aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    3495             :                                Anum_pg_parameter_acl_paracl,
    3496             :                                &isNull);
    3497           0 :     if (isNull)
    3498             :     {
    3499             :         /* No ACL, so build default ACL */
    3500           0 :         acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3501           0 :         aclDatum = (Datum) 0;
    3502             :     }
    3503             :     else
    3504             :     {
    3505             :         /* detoast ACL if necessary */
    3506           0 :         acl = DatumGetAclP(aclDatum);
    3507             :     }
    3508             : 
    3509           0 :     result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3510             : 
    3511             :     /* if we have a detoasted copy, free it */
    3512           0 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3513           0 :         pfree(acl);
    3514             : 
    3515           0 :     ReleaseSysCache(tuple);
    3516             : 
    3517           0 :     return result;
    3518             : }
    3519             : 
    3520             : /*
    3521             :  * Routine for examining a user's privileges for a largeobject
    3522             :  *
    3523             :  * When a large object is opened for reading, it is opened relative to the
    3524             :  * caller's snapshot, but when it is opened for writing, a current
    3525             :  * MVCC snapshot will be used.  See doc/src/sgml/lobj.sgml.  This function
    3526             :  * takes a snapshot argument so that the permissions check can be made
    3527             :  * relative to the same snapshot that will be used to read the underlying
    3528             :  * data.  The caller will actually pass NULL for an instantaneous MVCC
    3529             :  * snapshot, since all we do with the snapshot argument is pass it through
    3530             :  * to systable_beginscan().
    3531             :  */
    3532             : static AclMode
    3533         774 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
    3534             :                                 AclMode mask, AclMaskHow how,
    3535             :                                 Snapshot snapshot)
    3536             : {
    3537             :     AclMode     result;
    3538             :     Relation    pg_lo_meta;
    3539             :     ScanKeyData entry[1];
    3540             :     SysScanDesc scan;
    3541             :     HeapTuple   tuple;
    3542             :     Datum       aclDatum;
    3543             :     bool        isNull;
    3544             :     Acl        *acl;
    3545             :     Oid         ownerId;
    3546             : 
    3547             :     /* Superusers bypass all permission checking. */
    3548         774 :     if (superuser_arg(roleid))
    3549         480 :         return mask;
    3550             : 
    3551             :     /*
    3552             :      * Get the largeobject's ACL from pg_largeobject_metadata
    3553             :      */
    3554         294 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
    3555             :                             AccessShareLock);
    3556             : 
    3557         294 :     ScanKeyInit(&entry[0],
    3558             :                 Anum_pg_largeobject_metadata_oid,
    3559             :                 BTEqualStrategyNumber, F_OIDEQ,
    3560             :                 ObjectIdGetDatum(lobj_oid));
    3561             : 
    3562         294 :     scan = systable_beginscan(pg_lo_meta,
    3563             :                               LargeObjectMetadataOidIndexId, true,
    3564             :                               snapshot, 1, entry);
    3565             : 
    3566         294 :     tuple = systable_getnext(scan);
    3567         294 :     if (!HeapTupleIsValid(tuple))
    3568           0 :         ereport(ERROR,
    3569             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3570             :                  errmsg("large object %u does not exist", lobj_oid)));
    3571             : 
    3572         294 :     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
    3573             : 
    3574         294 :     aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
    3575             :                             RelationGetDescr(pg_lo_meta), &isNull);
    3576             : 
    3577         294 :     if (isNull)
    3578             :     {
    3579             :         /* No ACL, so build default ACL */
    3580          72 :         acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    3581          72 :         aclDatum = (Datum) 0;
    3582             :     }
    3583             :     else
    3584             :     {
    3585             :         /* detoast ACL if necessary */
    3586         222 :         acl = DatumGetAclP(aclDatum);
    3587             :     }
    3588             : 
    3589         294 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3590             : 
    3591             :     /* if we have a detoasted copy, free it */
    3592         294 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3593         294 :         pfree(acl);
    3594             : 
    3595         294 :     systable_endscan(scan);
    3596             : 
    3597         294 :     table_close(pg_lo_meta, AccessShareLock);
    3598             : 
    3599         294 :     return result;
    3600             : }
    3601             : 
    3602             : /*
    3603             :  * Routine for examining a user's privileges for a namespace, with is_missing
    3604             :  */
    3605             : static AclMode
    3606      961100 : pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
    3607             :                          AclMode mask, AclMaskHow how,
    3608             :                          bool *is_missing)
    3609             : {
    3610             :     AclMode     result;
    3611             :     HeapTuple   tuple;
    3612             :     Datum       aclDatum;
    3613             :     bool        isNull;
    3614             :     Acl        *acl;
    3615             :     Oid         ownerId;
    3616             : 
    3617             :     /* Superusers bypass all permission checking. */
    3618      961100 :     if (superuser_arg(roleid))
    3619      943822 :         return mask;
    3620             : 
    3621             :     /*
    3622             :      * If we have been assigned this namespace as a temp namespace, check to
    3623             :      * make sure we have CREATE TEMP permission on the database, and if so act
    3624             :      * as though we have all standard (but not GRANT OPTION) permissions on
    3625             :      * the namespace.  If we don't have CREATE TEMP, act as though we have
    3626             :      * only USAGE (and not CREATE) rights.
    3627             :      *
    3628             :      * This may seem redundant given the check in InitTempTableNamespace, but
    3629             :      * it really isn't since current user ID may have changed since then. The
    3630             :      * upshot of this behavior is that a SECURITY DEFINER function can create
    3631             :      * temp tables that can then be accessed (if permission is granted) by
    3632             :      * code in the same session that doesn't have permissions to create temp
    3633             :      * tables.
    3634             :      *
    3635             :      * XXX Would it be safe to ereport a special error message as
    3636             :      * InitTempTableNamespace does?  Returning zero here means we'll get a
    3637             :      * generic "permission denied for schema pg_temp_N" message, which is not
    3638             :      * remarkably user-friendly.
    3639             :      */
    3640       17278 :     if (isTempNamespace(nsp_oid))
    3641             :     {
    3642         314 :         if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
    3643             :                                 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
    3644         314 :             return mask & ACL_ALL_RIGHTS_SCHEMA;
    3645             :         else
    3646           0 :             return mask & ACL_USAGE;
    3647             :     }
    3648             : 
    3649             :     /*
    3650             :      * Get the schema's ACL from pg_namespace
    3651             :      */
    3652       16964 :     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
    3653       16964 :     if (!HeapTupleIsValid(tuple))
    3654             :     {
    3655           0 :         if (is_missing != NULL)
    3656             :         {
    3657             :             /* return "no privileges" instead of throwing an error */
    3658           0 :             *is_missing = true;
    3659           0 :             return 0;
    3660             :         }
    3661             :         else
    3662           0 :             ereport(ERROR,
    3663             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
    3664             :                      errmsg("schema with OID %u does not exist", nsp_oid)));
    3665             :     }
    3666             : 
    3667       16964 :     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
    3668             : 
    3669       16964 :     aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
    3670             :                                &isNull);
    3671       16964 :     if (isNull)
    3672             :     {
    3673             :         /* No ACL, so build default ACL */
    3674         304 :         acl = acldefault(OBJECT_SCHEMA, ownerId);
    3675         304 :         aclDatum = (Datum) 0;
    3676             :     }
    3677             :     else
    3678             :     {
    3679             :         /* detoast ACL if necessary */
    3680       16660 :         acl = DatumGetAclP(aclDatum);
    3681             :     }
    3682             : 
    3683       16964 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3684             : 
    3685             :     /* if we have a detoasted copy, free it */
    3686       16964 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3687       16964 :         pfree(acl);
    3688             : 
    3689       16964 :     ReleaseSysCache(tuple);
    3690             : 
    3691             :     /*
    3692             :      * Check if ACL_USAGE is being checked and, if so, and not set already as
    3693             :      * part of the result, then check if the user is a member of the
    3694             :      * pg_read_all_data or pg_write_all_data roles, which allow usage access
    3695             :      * to all schemas.
    3696             :      */
    3697       17026 :     if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
    3698         118 :         (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
    3699          56 :          has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
    3700          12 :         result |= ACL_USAGE;
    3701       16964 :     return result;
    3702             : }
    3703             : 
    3704             : /*
    3705             :  * Routine for examining a user's privileges for a type, with is_missing
    3706             :  */
    3707             : static AclMode
    3708      347782 : pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
    3709             :                     bool *is_missing)
    3710             : {
    3711             :     AclMode     result;
    3712             :     HeapTuple   tuple;
    3713             :     Form_pg_type typeForm;
    3714             :     Datum       aclDatum;
    3715             :     bool        isNull;
    3716             :     Acl        *acl;
    3717             :     Oid         ownerId;
    3718             : 
    3719             :     /* Bypass permission checks for superusers */
    3720      347782 :     if (superuser_arg(roleid))
    3721      343388 :         return mask;
    3722             : 
    3723             :     /*
    3724             :      * Must get the type's tuple from pg_type
    3725             :      */
    3726        4394 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
    3727        4394 :     if (!HeapTupleIsValid(tuple))
    3728             :     {
    3729           0 :         if (is_missing != NULL)
    3730             :         {
    3731             :             /* return "no privileges" instead of throwing an error */
    3732           0 :             *is_missing = true;
    3733           0 :             return 0;
    3734             :         }
    3735             :         else
    3736           0 :             ereport(ERROR,
    3737             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    3738             :                      errmsg("type with OID %u does not exist",
    3739             :                             type_oid)));
    3740             :     }
    3741        4394 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3742             : 
    3743             :     /*
    3744             :      * "True" array types don't manage permissions of their own; consult the
    3745             :      * element type instead.
    3746             :      */
    3747        4394 :     if (IsTrueArrayType(typeForm))
    3748             :     {
    3749          48 :         Oid         elttype_oid = typeForm->typelem;
    3750             : 
    3751          48 :         ReleaseSysCache(tuple);
    3752             : 
    3753          48 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
    3754          48 :         if (!HeapTupleIsValid(tuple))
    3755             :         {
    3756           0 :             if (is_missing != NULL)
    3757             :             {
    3758             :                 /* return "no privileges" instead of throwing an error */
    3759           0 :                 *is_missing = true;
    3760           0 :                 return 0;
    3761             :             }
    3762             :             else
    3763           0 :                 ereport(ERROR,
    3764             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    3765             :                          errmsg("type with OID %u does not exist",
    3766             :                                 elttype_oid)));
    3767             :         }
    3768          48 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3769             :     }
    3770             : 
    3771             :     /*
    3772             :      * Likewise, multirange types don't manage their own permissions; consult
    3773             :      * the associated range type.  (Note we must do this after the array step
    3774             :      * to get the right answer for arrays of multiranges.)
    3775             :      */
    3776        4394 :     if (typeForm->typtype == TYPTYPE_MULTIRANGE)
    3777             :     {
    3778          12 :         Oid         rangetype = get_multirange_range(typeForm->oid);
    3779             : 
    3780          12 :         ReleaseSysCache(tuple);
    3781             : 
    3782          12 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
    3783          12 :         if (!HeapTupleIsValid(tuple))
    3784             :         {
    3785           0 :             if (is_missing != NULL)
    3786             :             {
    3787             :                 /* return "no privileges" instead of throwing an error */
    3788           0 :                 *is_missing = true;
    3789           0 :                 return 0;
    3790             :             }
    3791             :             else
    3792           0 :                 ereport(ERROR,
    3793             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    3794             :                          errmsg("type with OID %u does not exist",
    3795             :                                 rangetype)));
    3796             :         }
    3797          12 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3798             :     }
    3799             : 
    3800             :     /*
    3801             :      * Now get the type's owner and ACL from the tuple
    3802             :      */
    3803        4394 :     ownerId = typeForm->typowner;
    3804             : 
    3805        4394 :     aclDatum = SysCacheGetAttr(TYPEOID, tuple,
    3806             :                                Anum_pg_type_typacl, &isNull);
    3807        4394 :     if (isNull)
    3808             :     {
    3809             :         /* No ACL, so build default ACL */
    3810        4160 :         acl = acldefault(OBJECT_TYPE, ownerId);
    3811        4160 :         aclDatum = (Datum) 0;
    3812             :     }
    3813             :     else
    3814             :     {
    3815             :         /* detoast rel's ACL if necessary */
    3816         234 :         acl = DatumGetAclP(aclDatum);
    3817             :     }
    3818             : 
    3819        4394 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3820             : 
    3821             :     /* if we have a detoasted copy, free it */
    3822        4394 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3823        4394 :         pfree(acl);
    3824             : 
    3825        4394 :     ReleaseSysCache(tuple);
    3826             : 
    3827        4394 :     return result;
    3828             : }
    3829             : 
    3830             : /*
    3831             :  * Exported generic routine for checking a user's access privileges to an object
    3832             :  */
    3833             : AclResult
    3834     3171440 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
    3835             : {
    3836     3171440 :     return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
    3837             : }
    3838             : 
    3839             : /*
    3840             :  * Exported generic routine for checking a user's access privileges to an
    3841             :  * object, with is_missing
    3842             :  */
    3843             : AclResult
    3844     3171862 : object_aclcheck_ext(Oid classid, Oid objectid,
    3845             :                     Oid roleid, AclMode mode,
    3846             :                     bool *is_missing)
    3847             : {
    3848     3171862 :     if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
    3849             :                            is_missing) != 0)
    3850     3171272 :         return ACLCHECK_OK;
    3851             :     else
    3852         590 :         return ACLCHECK_NO_PRIV;
    3853             : }
    3854             : 
    3855             : /*
    3856             :  * Exported routine for checking a user's access privileges to a column
    3857             :  *
    3858             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    3859             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    3860             :  * ACLCHECK_NO_PRIV).
    3861             :  *
    3862             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3863             :  * column are considered here.
    3864             :  */
    3865             : AclResult
    3866        4090 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
    3867             :                       Oid roleid, AclMode mode)
    3868             : {
    3869        4090 :     return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
    3870             : }
    3871             : 
    3872             : 
    3873             : /*
    3874             :  * Exported routine for checking a user's access privileges to a column,
    3875             :  * with is_missing
    3876             :  */
    3877             : AclResult
    3878        7798 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
    3879             :                           Oid roleid, AclMode mode, bool *is_missing)
    3880             : {
    3881        7798 :     if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
    3882             :                                  ACLMASK_ANY, is_missing) != 0)
    3883        2296 :         return ACLCHECK_OK;
    3884             :     else
    3885        5502 :         return ACLCHECK_NO_PRIV;
    3886             : }
    3887             : 
    3888             : /*
    3889             :  * Exported routine for checking a user's access privileges to any/all columns
    3890             :  *
    3891             :  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
    3892             :  * privileges identified by 'mode' on any non-dropped column in the relation;
    3893             :  * otherwise returns a suitable error code (in practice, always
    3894             :  * ACLCHECK_NO_PRIV).
    3895             :  *
    3896             :  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
    3897             :  * privileges identified by 'mode' on each non-dropped column in the relation
    3898             :  * (and there must be at least one such column); otherwise returns a suitable
    3899             :  * error code (in practice, always ACLCHECK_NO_PRIV).
    3900             :  *
    3901             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3902             :  * column(s) are considered here.
    3903             :  *
    3904             :  * Note: system columns are not considered here; there are cases where that
    3905             :  * might be appropriate but there are also cases where it wouldn't.
    3906             :  */
    3907             : AclResult
    3908         174 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
    3909             :                           AclMaskHow how)
    3910             : {
    3911         174 :     return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
    3912             : }
    3913             : 
    3914             : /*
    3915             :  * Exported routine for checking a user's access privileges to any/all columns,
    3916             :  * with is_missing
    3917             :  */
    3918             : AclResult
    3919         174 : pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
    3920             :                               AclMode mode, AclMaskHow how,
    3921             :                               bool *is_missing)
    3922             : {
    3923             :     AclResult   result;
    3924             :     HeapTuple   classTuple;
    3925             :     Form_pg_class classForm;
    3926             :     Oid         ownerId;
    3927             :     AttrNumber  nattrs;
    3928             :     AttrNumber  curr_att;
    3929             : 
    3930             :     /*
    3931             :      * Must fetch pg_class row to get owner ID and number of attributes.
    3932             :      */
    3933         174 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3934         174 :     if (!HeapTupleIsValid(classTuple))
    3935             :     {
    3936           0 :         if (is_missing != NULL)
    3937             :         {
    3938             :             /* return "no privileges" instead of throwing an error */
    3939           0 :             *is_missing = true;
    3940           0 :             return ACLCHECK_NO_PRIV;
    3941             :         }
    3942             :         else
    3943           0 :             ereport(ERROR,
    3944             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3945             :                      errmsg("relation with OID %u does not exist",
    3946             :                             table_oid)));
    3947             :     }
    3948         174 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3949             : 
    3950         174 :     ownerId = classForm->relowner;
    3951         174 :     nattrs = classForm->relnatts;
    3952             : 
    3953         174 :     ReleaseSysCache(classTuple);
    3954             : 
    3955             :     /*
    3956             :      * Initialize result in case there are no non-dropped columns.  We want to
    3957             :      * report failure in such cases for either value of 'how'.
    3958             :      */
    3959         174 :     result = ACLCHECK_NO_PRIV;
    3960             : 
    3961         426 :     for (curr_att = 1; curr_att <= nattrs; curr_att++)
    3962             :     {
    3963             :         HeapTuple   attTuple;
    3964             :         Datum       aclDatum;
    3965             :         bool        isNull;
    3966             :         Acl        *acl;
    3967             :         AclMode     attmask;
    3968             : 
    3969         342 :         attTuple = SearchSysCache2(ATTNUM,
    3970             :                                    ObjectIdGetDatum(table_oid),
    3971             :                                    Int16GetDatum(curr_att));
    3972             : 
    3973             :         /*
    3974             :          * Lookup failure probably indicates that the table was just dropped,
    3975             :          * but we'll treat it the same as a dropped column rather than
    3976             :          * throwing error.
    3977             :          */
    3978         342 :         if (!HeapTupleIsValid(attTuple))
    3979          18 :             continue;
    3980             : 
    3981             :         /* ignore dropped columns */
    3982         342 :         if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    3983             :         {
    3984          18 :             ReleaseSysCache(attTuple);
    3985          18 :             continue;
    3986             :         }
    3987             : 
    3988         324 :         aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
    3989             :                                    &isNull);
    3990             : 
    3991             :         /*
    3992             :          * Here we hard-wire knowledge that the default ACL for a column
    3993             :          * grants no privileges, so that we can fall out quickly in the very
    3994             :          * common case where attacl is null.
    3995             :          */
    3996         324 :         if (isNull)
    3997         168 :             attmask = 0;
    3998             :         else
    3999             :         {
    4000             :             /* detoast column's ACL if necessary */
    4001         156 :             acl = DatumGetAclP(aclDatum);
    4002             : 
    4003         156 :             attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
    4004             : 
    4005             :             /* if we have a detoasted copy, free it */
    4006         156 :             if ((Pointer) acl != DatumGetPointer(aclDatum))
    4007         156 :                 pfree(acl);
    4008             :         }
    4009             : 
    4010         324 :         ReleaseSysCache(attTuple);
    4011             : 
    4012         324 :         if (attmask != 0)
    4013             :         {
    4014         138 :             result = ACLCHECK_OK;
    4015         138 :             if (how == ACLMASK_ANY)
    4016          90 :                 break;          /* succeed on any success */
    4017             :         }
    4018             :         else
    4019             :         {
    4020         186 :             result = ACLCHECK_NO_PRIV;
    4021         186 :             if (how == ACLMASK_ALL)
    4022          48 :                 break;          /* fail on any failure */
    4023             :         }
    4024             :     }
    4025             : 
    4026         174 :     return result;
    4027             : }
    4028             : 
    4029             : /*
    4030             :  * Exported routine for checking a user's access privileges to a table
    4031             :  *
    4032             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    4033             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    4034             :  * ACLCHECK_NO_PRIV).
    4035             :  */
    4036             : AclResult
    4037     2367874 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
    4038             : {
    4039     2367874 :     return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
    4040             : }
    4041             : 
    4042             : /*
    4043             :  * Exported routine for checking a user's access privileges to a table,
    4044             :  * with is_missing
    4045             :  */
    4046             : AclResult
    4047     2371698 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
    4048             :                       AclMode mode, bool *is_missing)
    4049             : {
    4050     2371698 :     if (pg_class_aclmask_ext(table_oid, roleid, mode,
    4051             :                              ACLMASK_ANY, is_missing) != 0)
    4052     2367636 :         return ACLCHECK_OK;
    4053             :     else
    4054        4062 :         return ACLCHECK_NO_PRIV;
    4055             : }
    4056             : 
    4057             : /*
    4058             :  * Exported routine for checking a user's access privileges to a configuration
    4059             :  * parameter (GUC), identified by GUC name.
    4060             :  */
    4061             : AclResult
    4062         160 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
    4063             : {
    4064         160 :     if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
    4065          68 :         return ACLCHECK_OK;
    4066             :     else
    4067          92 :         return ACLCHECK_NO_PRIV;
    4068             : }
    4069             : 
    4070             : /*
    4071             :  * Exported routine for checking a user's access privileges to a largeobject
    4072             :  */
    4073             : AclResult
    4074         774 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
    4075             :                                  Snapshot snapshot)
    4076             : {
    4077         774 :     if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
    4078             :                                         ACLMASK_ANY, snapshot) != 0)
    4079         648 :         return ACLCHECK_OK;
    4080             :     else
    4081         126 :         return ACLCHECK_NO_PRIV;
    4082             : }
    4083             : 
    4084             : /*
    4085             :  * Generic ownership check for an object
    4086             :  */
    4087             : bool
    4088      488050 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
    4089             : {
    4090             :     int         cacheid;
    4091             :     Oid         ownerId;
    4092             : 
    4093             :     /* Superusers bypass all permission checking. */
    4094      488050 :     if (superuser_arg(roleid))
    4095      477094 :         return true;
    4096             : 
    4097             :     /* For large objects, the catalog to consult is pg_largeobject_metadata */
    4098       10956 :     if (classid == LargeObjectRelationId)
    4099          24 :         classid = LargeObjectMetadataRelationId;
    4100             : 
    4101       10956 :     cacheid = get_object_catcache_oid(classid);
    4102       10956 :     if (cacheid != -1)
    4103             :     {
    4104             :         /* we can get the object's tuple from the syscache */
    4105             :         HeapTuple   tuple;
    4106             : 
    4107       10928 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    4108       10928 :         if (!HeapTupleIsValid(tuple))
    4109           0 :             elog(ERROR, "cache lookup failed for %s %u",
    4110             :                  get_object_class_descr(classid), objectid);
    4111             : 
    4112       10928 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    4113             :                                                           tuple,
    4114       10928 :                                                           get_object_attnum_owner(classid)));
    4115       10928 :         ReleaseSysCache(tuple);
    4116             :     }
    4117             :     else
    4118             :     {
    4119             :         /* for catalogs without an appropriate syscache */
    4120             :         Relation    rel;
    4121             :         ScanKeyData entry[1];
    4122             :         SysScanDesc scan;
    4123             :         HeapTuple   tuple;
    4124             :         bool        isnull;
    4125             : 
    4126          28 :         rel = table_open(classid, AccessShareLock);
    4127             : 
    4128          56 :         ScanKeyInit(&entry[0],
    4129          28 :                     get_object_attnum_oid(classid),
    4130             :                     BTEqualStrategyNumber, F_OIDEQ,
    4131             :                     ObjectIdGetDatum(objectid));
    4132             : 
    4133          28 :         scan = systable_beginscan(rel,
    4134             :                                   get_object_oid_index(classid), true,
    4135             :                                   NULL, 1, entry);
    4136             : 
    4137          28 :         tuple = systable_getnext(scan);
    4138          28 :         if (!HeapTupleIsValid(tuple))
    4139           0 :             elog(ERROR, "could not find tuple for %s %u",
    4140             :                  get_object_class_descr(classid), objectid);
    4141             : 
    4142          28 :         ownerId = DatumGetObjectId(heap_getattr(tuple,
    4143          28 :                                                 get_object_attnum_owner(classid),
    4144             :                                                 RelationGetDescr(rel),
    4145             :                                                 &isnull));
    4146             :         Assert(!isnull);
    4147             : 
    4148          28 :         systable_endscan(scan);
    4149          28 :         table_close(rel, AccessShareLock);
    4150             :     }
    4151             : 
    4152       10956 :     return has_privs_of_role(roleid, ownerId);
    4153             : }
    4154             : 
    4155             : /*
    4156             :  * Check whether specified role has CREATEROLE privilege (or is a superuser)
    4157             :  *
    4158             :  * Note: roles do not have owners per se; instead we use this test in
    4159             :  * places where an ownership-like permissions test is needed for a role.
    4160             :  * Be sure to apply it to the role trying to do the operation, not the
    4161             :  * role being operated on!  Also note that this generally should not be
    4162             :  * considered enough privilege if the target role is a superuser.
    4163             :  * (We don't handle that consideration here because we want to give a
    4164             :  * separate error message for such cases, so the caller has to deal with it.)
    4165             :  */
    4166             : bool
    4167        2466 : has_createrole_privilege(Oid roleid)
    4168             : {
    4169        2466 :     bool        result = false;
    4170             :     HeapTuple   utup;
    4171             : 
    4172             :     /* Superusers bypass all permission checking. */
    4173        2466 :     if (superuser_arg(roleid))
    4174        1936 :         return true;
    4175             : 
    4176         530 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4177         530 :     if (HeapTupleIsValid(utup))
    4178             :     {
    4179         530 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
    4180         530 :         ReleaseSysCache(utup);
    4181             :     }
    4182         530 :     return result;
    4183             : }
    4184             : 
    4185             : bool
    4186        5020 : has_bypassrls_privilege(Oid roleid)
    4187             : {
    4188        5020 :     bool        result = false;
    4189             :     HeapTuple   utup;
    4190             : 
    4191             :     /* Superusers bypass all permission checking. */
    4192        5020 :     if (superuser_arg(roleid))
    4193        1652 :         return true;
    4194             : 
    4195        3368 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4196        3368 :     if (HeapTupleIsValid(utup))
    4197             :     {
    4198        3368 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
    4199        3368 :         ReleaseSysCache(utup);
    4200             :     }
    4201        3368 :     return result;
    4202             : }
    4203             : 
    4204             : /*
    4205             :  * Fetch pg_default_acl entry for given role, namespace and object type
    4206             :  * (object type must be given in pg_default_acl's encoding).
    4207             :  * Returns NULL if no such entry.
    4208             :  */
    4209             : static Acl *
    4210      165644 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
    4211             : {
    4212      165644 :     Acl        *result = NULL;
    4213             :     HeapTuple   tuple;
    4214             : 
    4215      165644 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    4216             :                             ObjectIdGetDatum(roleId),
    4217             :                             ObjectIdGetDatum(nsp_oid),
    4218             :                             CharGetDatum(objtype));
    4219             : 
    4220      165644 :     if (HeapTupleIsValid(tuple))
    4221             :     {
    4222             :         Datum       aclDatum;
    4223             :         bool        isNull;
    4224             : 
    4225         264 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    4226             :                                    Anum_pg_default_acl_defaclacl,
    4227             :                                    &isNull);
    4228         264 :         if (!isNull)
    4229         264 :             result = DatumGetAclPCopy(aclDatum);
    4230         264 :         ReleaseSysCache(tuple);
    4231             :     }
    4232             : 
    4233      165644 :     return result;
    4234             : }
    4235             : 
    4236             : /*
    4237             :  * Get default permissions for newly created object within given schema
    4238             :  *
    4239             :  * Returns NULL if built-in system defaults should be used.
    4240             :  *
    4241             :  * If the result is not NULL, caller must call recordDependencyOnNewAcl
    4242             :  * once the OID of the new object is known.
    4243             :  */
    4244             : Acl *
    4245       82822 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
    4246             : {
    4247             :     Acl        *result;
    4248             :     Acl        *glob_acl;
    4249             :     Acl        *schema_acl;
    4250             :     Acl        *def_acl;
    4251             :     char        defaclobjtype;
    4252             : 
    4253             :     /*
    4254             :      * Use NULL during bootstrap, since pg_default_acl probably isn't there
    4255             :      * yet.
    4256             :      */
    4257       82822 :     if (IsBootstrapProcessingMode())
    4258           0 :         return NULL;
    4259             : 
    4260             :     /* Check if object type is supported in pg_default_acl */
    4261       82822 :     switch (objtype)
    4262             :     {
    4263       55600 :         case OBJECT_TABLE:
    4264       55600 :             defaclobjtype = DEFACLOBJ_RELATION;
    4265       55600 :             break;
    4266             : 
    4267        1792 :         case OBJECT_SEQUENCE:
    4268        1792 :             defaclobjtype = DEFACLOBJ_SEQUENCE;
    4269        1792 :             break;
    4270             : 
    4271       17606 :         case OBJECT_FUNCTION:
    4272       17606 :             defaclobjtype = DEFACLOBJ_FUNCTION;
    4273       17606 :             break;
    4274             : 
    4275        6660 :         case OBJECT_TYPE:
    4276        6660 :             defaclobjtype = DEFACLOBJ_TYPE;
    4277        6660 :             break;
    4278             : 
    4279        1028 :         case OBJECT_SCHEMA:
    4280        1028 :             defaclobjtype = DEFACLOBJ_NAMESPACE;
    4281        1028 :             break;
    4282             : 
    4283         136 :         case OBJECT_LARGEOBJECT:
    4284         136 :             defaclobjtype = DEFACLOBJ_LARGEOBJECT;
    4285         136 :             break;
    4286             : 
    4287           0 :         default:
    4288           0 :             return NULL;
    4289             :     }
    4290             : 
    4291             :     /* Look up the relevant pg_default_acl entries */
    4292       82822 :     glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
    4293       82822 :     schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
    4294             : 
    4295             :     /* Quick out if neither entry exists */
    4296       82822 :     if (glob_acl == NULL && schema_acl == NULL)
    4297       82612 :         return NULL;
    4298             : 
    4299             :     /* We need to know the hard-wired default value, too */
    4300         210 :     def_acl = acldefault(objtype, ownerId);
    4301             : 
    4302             :     /* If there's no global entry, substitute the hard-wired default */
    4303         210 :     if (glob_acl == NULL)
    4304          18 :         glob_acl = def_acl;
    4305             : 
    4306             :     /* Merge in any per-schema privileges */
    4307         210 :     result = aclmerge(glob_acl, schema_acl, ownerId);
    4308             : 
    4309             :     /*
    4310             :      * For efficiency, we want to return NULL if the result equals default.
    4311             :      * This requires sorting both arrays to get an accurate comparison.
    4312             :      */
    4313         210 :     aclitemsort(result);
    4314         210 :     aclitemsort(def_acl);
    4315         210 :     if (aclequal(result, def_acl))
    4316          24 :         result = NULL;
    4317             : 
    4318         210 :     return result;
    4319             : }
    4320             : 
    4321             : /*
    4322             :  * Record dependencies on roles mentioned in a new object's ACL.
    4323             :  */
    4324             : void
    4325       86120 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
    4326             :                          Oid ownerId, Acl *acl)
    4327             : {
    4328             :     int         nmembers;
    4329             :     Oid        *members;
    4330             : 
    4331             :     /* Nothing to do if ACL is defaulted */
    4332       86120 :     if (acl == NULL)
    4333       85934 :         return;
    4334             : 
    4335             :     /* Extract roles mentioned in ACL */
    4336         186 :     nmembers = aclmembers(acl, &members);
    4337             : 
    4338             :     /* Update the shared dependency ACL info */
    4339         186 :     updateAclDependencies(classId, objectId, objsubId,
    4340             :                           ownerId,
    4341             :                           0, NULL,
    4342             :                           nmembers, members);
    4343             : }
    4344             : 
    4345             : /*
    4346             :  * Record initial privileges for the top-level object passed in.
    4347             :  *
    4348             :  * For the object passed in, this will record its ACL (if any) and the ACLs of
    4349             :  * any sub-objects (eg: columns) into pg_init_privs.
    4350             :  */
    4351             : void
    4352          96 : recordExtObjInitPriv(Oid objoid, Oid classoid)
    4353             : {
    4354             :     /*
    4355             :      * pg_class / pg_attribute
    4356             :      *
    4357             :      * If this is a relation then we need to see if there are any sub-objects
    4358             :      * (eg: columns) for it and, if so, be sure to call
    4359             :      * recordExtensionInitPrivWorker() for each one.
    4360             :      */
    4361          96 :     if (classoid == RelationRelationId)
    4362             :     {
    4363             :         Form_pg_class pg_class_tuple;
    4364             :         Datum       aclDatum;
    4365             :         bool        isNull;
    4366             :         HeapTuple   tuple;
    4367             : 
    4368          16 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4369          16 :         if (!HeapTupleIsValid(tuple))
    4370           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4371          16 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    4372             : 
    4373             :         /*
    4374             :          * Indexes don't have permissions, neither do the pg_class rows for
    4375             :          * composite types.  (These cases are unreachable given the
    4376             :          * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
    4377             :          */
    4378          16 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4379          16 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4380          16 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4381             :         {
    4382           0 :             ReleaseSysCache(tuple);
    4383           0 :             return;
    4384             :         }
    4385             : 
    4386             :         /*
    4387             :          * If this isn't a sequence then it's possibly going to have
    4388             :          * column-level ACLs associated with it.
    4389             :          */
    4390          16 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4391             :         {
    4392             :             AttrNumber  curr_att;
    4393          14 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4394             : 
    4395          38 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4396             :             {
    4397             :                 HeapTuple   attTuple;
    4398             :                 Datum       attaclDatum;
    4399             : 
    4400          24 :                 attTuple = SearchSysCache2(ATTNUM,
    4401             :                                            ObjectIdGetDatum(objoid),
    4402             :                                            Int16GetDatum(curr_att));
    4403             : 
    4404          24 :                 if (!HeapTupleIsValid(attTuple))
    4405           0 :                     continue;
    4406             : 
    4407             :                 /* ignore dropped columns */
    4408          24 :                 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    4409             :                 {
    4410           2 :                     ReleaseSysCache(attTuple);
    4411           2 :                     continue;
    4412             :                 }
    4413             : 
    4414          22 :                 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
    4415             :                                               Anum_pg_attribute_attacl,
    4416             :                                               &isNull);
    4417             : 
    4418             :                 /* no need to do anything for a NULL ACL */
    4419          22 :                 if (isNull)
    4420             :                 {
    4421          18 :                     ReleaseSysCache(attTuple);
    4422          18 :                     continue;
    4423             :                 }
    4424             : 
    4425           4 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
    4426           4 :                                               DatumGetAclP(attaclDatum));
    4427             : 
    4428           4 :                 ReleaseSysCache(attTuple);
    4429             :             }
    4430             :         }
    4431             : 
    4432          16 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    4433             :                                    &isNull);
    4434             : 
    4435             :         /* Add the record, if any, for the top-level object */
    4436          16 :         if (!isNull)
    4437           8 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4438           8 :                                           DatumGetAclP(aclDatum));
    4439             : 
    4440          16 :         ReleaseSysCache(tuple);
    4441             :     }
    4442          80 :     else if (classoid == LargeObjectRelationId)
    4443             :     {
    4444             :         /* For large objects, we must consult pg_largeobject_metadata */
    4445             :         Datum       aclDatum;
    4446             :         bool        isNull;
    4447             :         HeapTuple   tuple;
    4448             :         ScanKeyData entry[1];
    4449             :         SysScanDesc scan;
    4450             :         Relation    relation;
    4451             : 
    4452             :         /*
    4453             :          * Note: this is dead code, given that we don't allow large objects to
    4454             :          * be made extension members.  But it seems worth carrying in case
    4455             :          * some future caller of this function has need for it.
    4456             :          */
    4457           0 :         relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
    4458             : 
    4459             :         /* There's no syscache for pg_largeobject_metadata */
    4460           0 :         ScanKeyInit(&entry[0],
    4461             :                     Anum_pg_largeobject_metadata_oid,
    4462             :                     BTEqualStrategyNumber, F_OIDEQ,
    4463             :                     ObjectIdGetDatum(objoid));
    4464             : 
    4465           0 :         scan = systable_beginscan(relation,
    4466             :                                   LargeObjectMetadataOidIndexId, true,
    4467             :                                   NULL, 1, entry);
    4468             : 
    4469           0 :         tuple = systable_getnext(scan);
    4470           0 :         if (!HeapTupleIsValid(tuple))
    4471           0 :             elog(ERROR, "could not find tuple for large object %u", objoid);
    4472             : 
    4473           0 :         aclDatum = heap_getattr(tuple,
    4474             :                                 Anum_pg_largeobject_metadata_lomacl,
    4475             :                                 RelationGetDescr(relation), &isNull);
    4476             : 
    4477             :         /* Add the record, if any, for the top-level object */
    4478           0 :         if (!isNull)
    4479           0 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4480           0 :                                           DatumGetAclP(aclDatum));
    4481             : 
    4482           0 :         systable_endscan(scan);
    4483             :     }
    4484             :     /* This will error on unsupported classoid. */
    4485          80 :     else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
    4486             :     {
    4487             :         int         cacheid;
    4488             :         Datum       aclDatum;
    4489             :         bool        isNull;
    4490             :         HeapTuple   tuple;
    4491             : 
    4492          58 :         cacheid = get_object_catcache_oid(classoid);
    4493          58 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
    4494          58 :         if (!HeapTupleIsValid(tuple))
    4495           0 :             elog(ERROR, "cache lookup failed for %s %u",
    4496             :                  get_object_class_descr(classoid), objoid);
    4497             : 
    4498          58 :         aclDatum = SysCacheGetAttr(cacheid, tuple,
    4499          58 :                                    get_object_attnum_acl(classoid),
    4500             :                                    &isNull);
    4501             : 
    4502             :         /* Add the record, if any, for the top-level object */
    4503          58 :         if (!isNull)
    4504          10 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4505          10 :                                           DatumGetAclP(aclDatum));
    4506             : 
    4507          58 :         ReleaseSysCache(tuple);
    4508             :     }
    4509             : }
    4510             : 
    4511             : /*
    4512             :  * For the object passed in, remove its ACL and the ACLs of any object subIds
    4513             :  * from pg_init_privs (via recordExtensionInitPrivWorker()).
    4514             :  */
    4515             : void
    4516         352 : removeExtObjInitPriv(Oid objoid, Oid classoid)
    4517             : {
    4518             :     /*
    4519             :      * If this is a relation then we need to see if there are any sub-objects
    4520             :      * (eg: columns) for it and, if so, be sure to call
    4521             :      * recordExtensionInitPrivWorker() for each one.
    4522             :      */
    4523         352 :     if (classoid == RelationRelationId)
    4524             :     {
    4525             :         Form_pg_class pg_class_tuple;
    4526             :         HeapTuple   tuple;
    4527             : 
    4528          70 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4529          70 :         if (!HeapTupleIsValid(tuple))
    4530           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4531          70 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    4532             : 
    4533             :         /*
    4534             :          * Indexes don't have permissions, neither do the pg_class rows for
    4535             :          * composite types.  (These cases are unreachable given the
    4536             :          * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
    4537             :          */
    4538          70 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4539          70 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4540          70 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4541             :         {
    4542           0 :             ReleaseSysCache(tuple);
    4543           0 :             return;
    4544             :         }
    4545             : 
    4546             :         /*
    4547             :          * If this isn't a sequence then it's possibly going to have
    4548             :          * column-level ACLs associated with it.
    4549             :          */
    4550          70 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4551             :         {
    4552             :             AttrNumber  curr_att;
    4553          70 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4554             : 
    4555        2356 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4556             :             {
    4557             :                 HeapTuple   attTuple;
    4558             : 
    4559        2286 :                 attTuple = SearchSysCache2(ATTNUM,
    4560             :                                            ObjectIdGetDatum(objoid),
    4561             :                                            Int16GetDatum(curr_att));
    4562             : 
    4563        2286 :                 if (!HeapTupleIsValid(attTuple))
    4564           0 :                     continue;
    4565             : 
    4566             :                 /* when removing, remove all entries, even dropped columns */
    4567             : 
    4568        2286 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
    4569             : 
    4570        2286 :                 ReleaseSysCache(attTuple);
    4571             :             }
    4572             :         }
    4573             : 
    4574          70 :         ReleaseSysCache(tuple);
    4575             :     }
    4576             : 
    4577             :     /* Remove the record, if any, for the top-level object */
    4578         352 :     recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
    4579             : }
    4580             : 
    4581             : /*
    4582             :  * Record initial ACL for an extension object
    4583             :  *
    4584             :  * Can be called at any time, we check if 'creating_extension' is set and, if
    4585             :  * not, exit immediately.
    4586             :  *
    4587             :  * Pass in the object OID, the OID of the class (the OID of the table which
    4588             :  * the object is defined in) and the 'sub' id of the object (objsubid), if
    4589             :  * any.  If there is no 'sub' id (they are currently only used for columns of
    4590             :  * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
    4591             :  *
    4592             :  * If an ACL already exists for this object/sub-object then we will replace
    4593             :  * it with what is passed in.
    4594             :  *
    4595             :  * Passing in NULL for 'new_acl' will result in the entry for the object being
    4596             :  * removed, if one is found.
    4597             :  */
    4598             : static void
    4599       31628 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    4600             : {
    4601             :     /*
    4602             :      * Generally, we only record the initial privileges when an extension is
    4603             :      * being created, but because we don't actually use CREATE EXTENSION
    4604             :      * during binary upgrades with pg_upgrade, there is a variable to let us
    4605             :      * know that the GRANT and REVOKE statements being issued, while this
    4606             :      * variable is true, are for the initial privileges of the extension
    4607             :      * object and therefore we need to record them.
    4608             :      */
    4609       31628 :     if (!creating_extension && !binary_upgrade_record_init_privs)
    4610       30826 :         return;
    4611             : 
    4612         802 :     recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
    4613             : }
    4614             : 
    4615             : /*
    4616             :  * Record initial ACL for an extension object, worker.
    4617             :  *
    4618             :  * This will perform a wholesale replacement of the entire ACL for the object
    4619             :  * passed in, therefore be sure to pass in the complete new ACL to use.
    4620             :  *
    4621             :  * Generally speaking, do *not* use this function directly but instead use
    4622             :  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
    4623             :  * This function does *not* check if 'creating_extension' is set as it is also
    4624             :  * used when an object is added to or removed from an extension via ALTER
    4625             :  * EXTENSION ... ADD/DROP.
    4626             :  */
    4627             : static void
    4628        3462 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
    4629             :                               Acl *new_acl)
    4630             : {
    4631             :     Relation    relation;
    4632             :     ScanKeyData key[3];
    4633             :     SysScanDesc scan;
    4634             :     HeapTuple   tuple;
    4635             :     HeapTuple   oldtuple;
    4636             :     int         noldmembers;
    4637             :     int         nnewmembers;
    4638             :     Oid        *oldmembers;
    4639             :     Oid        *newmembers;
    4640             : 
    4641             :     /* We'll need the role membership of the new ACL. */
    4642        3462 :     nnewmembers = aclmembers(new_acl, &newmembers);
    4643             : 
    4644             :     /* Search pg_init_privs for an existing entry. */
    4645        3462 :     relation = table_open(InitPrivsRelationId, RowExclusiveLock);
    4646             : 
    4647        3462 :     ScanKeyInit(&key[0],
    4648             :                 Anum_pg_init_privs_objoid,
    4649             :                 BTEqualStrategyNumber, F_OIDEQ,
    4650             :                 ObjectIdGetDatum(objoid));
    4651        3462 :     ScanKeyInit(&key[1],
    4652             :                 Anum_pg_init_privs_classoid,
    4653             :                 BTEqualStrategyNumber, F_OIDEQ,
    4654             :                 ObjectIdGetDatum(classoid));
    4655        3462 :     ScanKeyInit(&key[2],
    4656             :                 Anum_pg_init_privs_objsubid,
    4657             :                 BTEqualStrategyNumber, F_INT4EQ,
    4658             :                 Int32GetDatum(objsubid));
    4659             : 
    4660        3462 :     scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
    4661             :                               NULL, 3, key);
    4662             : 
    4663             :     /* There should exist only one entry or none. */
    4664        3462 :     oldtuple = systable_getnext(scan);
    4665             : 
    4666             :     /* If we find an entry, update it with the latest ACL. */
    4667        3462 :     if (HeapTupleIsValid(oldtuple))
    4668             :     {
    4669         274 :         Datum       values[Natts_pg_init_privs] = {0};
    4670         274 :         bool        nulls[Natts_pg_init_privs] = {0};
    4671         274 :         bool        replace[Natts_pg_init_privs] = {0};
    4672             :         Datum       oldAclDatum;
    4673             :         bool        isNull;
    4674             :         Acl        *old_acl;
    4675             : 
    4676             :         /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
    4677         274 :         oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4678             :                                    RelationGetDescr(relation), &isNull);
    4679             :         Assert(!isNull);
    4680         274 :         old_acl = DatumGetAclP(oldAclDatum);
    4681         274 :         noldmembers = aclmembers(old_acl, &oldmembers);
    4682             : 
    4683         274 :         updateInitAclDependencies(classoid, objoid, objsubid,
    4684             :                                   noldmembers, oldmembers,
    4685             :                                   nnewmembers, newmembers);
    4686             : 
    4687             :         /* If we have a new ACL to set, then update the row with it. */
    4688         274 :         if (new_acl && ACL_NUM(new_acl) != 0)
    4689             :         {
    4690         176 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4691         176 :             replace[Anum_pg_init_privs_initprivs - 1] = true;
    4692             : 
    4693         176 :             oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
    4694             :                                          values, nulls, replace);
    4695             : 
    4696         176 :             CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
    4697             :         }
    4698             :         else
    4699             :         {
    4700             :             /* new_acl is NULL/empty, so delete the entry we found. */
    4701          98 :             CatalogTupleDelete(relation, &oldtuple->t_self);
    4702             :         }
    4703             :     }
    4704             :     else
    4705             :     {
    4706        3188 :         Datum       values[Natts_pg_init_privs] = {0};
    4707        3188 :         bool        nulls[Natts_pg_init_privs] = {0};
    4708             : 
    4709             :         /*
    4710             :          * Only add a new entry if the new ACL is non-NULL.
    4711             :          *
    4712             :          * If we are passed in a NULL ACL and no entry exists, we can just
    4713             :          * fall through and do nothing.
    4714             :          */
    4715        3188 :         if (new_acl && ACL_NUM(new_acl) != 0)
    4716             :         {
    4717             :             /* No entry found, so add it. */
    4718         642 :             values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
    4719         642 :             values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
    4720         642 :             values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
    4721             : 
    4722             :             /* This function only handles initial privileges of extensions */
    4723         642 :             values[Anum_pg_init_privs_privtype - 1] =
    4724         642 :                 CharGetDatum(INITPRIVS_EXTENSION);
    4725             : 
    4726         642 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4727             : 
    4728         642 :             tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
    4729             : 
    4730         642 :             CatalogTupleInsert(relation, tuple);
    4731             : 
    4732             :             /* Update pg_shdepend, too. */
    4733         642 :             noldmembers = 0;
    4734         642 :             oldmembers = NULL;
    4735             : 
    4736         642 :             updateInitAclDependencies(classoid, objoid, objsubid,
    4737             :                                       noldmembers, oldmembers,
    4738             :                                       nnewmembers, newmembers);
    4739             :         }
    4740             :     }
    4741             : 
    4742        3462 :     systable_endscan(scan);
    4743             : 
    4744             :     /* prevent error when processing objects multiple times */
    4745        3462 :     CommandCounterIncrement();
    4746             : 
    4747        3462 :     table_close(relation, RowExclusiveLock);
    4748        3462 : }
    4749             : 
    4750             : /*
    4751             :  * ReplaceRoleInInitPriv
    4752             :  *
    4753             :  * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
    4754             :  */
    4755             : void
    4756          24 : ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
    4757             :                       Oid classid, Oid objid, int32 objsubid)
    4758             : {
    4759             :     Relation    rel;
    4760             :     ScanKeyData key[3];
    4761             :     SysScanDesc scan;
    4762             :     HeapTuple   oldtuple;
    4763             :     Datum       oldAclDatum;
    4764             :     bool        isNull;
    4765             :     Acl        *old_acl;
    4766             :     Acl        *new_acl;
    4767             :     HeapTuple   newtuple;
    4768             :     int         noldmembers;
    4769             :     int         nnewmembers;
    4770             :     Oid        *oldmembers;
    4771             :     Oid        *newmembers;
    4772             : 
    4773             :     /* Search for existing pg_init_privs entry for the target object. */
    4774          24 :     rel = table_open(InitPrivsRelationId, RowExclusiveLock);
    4775             : 
    4776          24 :     ScanKeyInit(&key[0],
    4777             :                 Anum_pg_init_privs_objoid,
    4778             :                 BTEqualStrategyNumber, F_OIDEQ,
    4779             :                 ObjectIdGetDatum(objid));
    4780          24 :     ScanKeyInit(&key[1],
    4781             :                 Anum_pg_init_privs_classoid,
    4782             :                 BTEqualStrategyNumber, F_OIDEQ,
    4783             :                 ObjectIdGetDatum(classid));
    4784          24 :     ScanKeyInit(&key[2],
    4785             :                 Anum_pg_init_privs_objsubid,
    4786             :                 BTEqualStrategyNumber, F_INT4EQ,
    4787             :                 Int32GetDatum(objsubid));
    4788             : 
    4789          24 :     scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
    4790             :                               NULL, 3, key);
    4791             : 
    4792             :     /* There should exist only one entry or none. */
    4793          24 :     oldtuple = systable_getnext(scan);
    4794             : 
    4795          24 :     if (!HeapTupleIsValid(oldtuple))
    4796             :     {
    4797             :         /*
    4798             :          * Hmm, why are we here if there's no entry?  But pack up and go away
    4799             :          * quietly.
    4800             :          */
    4801           0 :         systable_endscan(scan);
    4802           0 :         table_close(rel, RowExclusiveLock);
    4803           0 :         return;
    4804             :     }
    4805             : 
    4806             :     /* Get a writable copy of the existing ACL. */
    4807          24 :     oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4808             :                                RelationGetDescr(rel), &isNull);
    4809             :     Assert(!isNull);
    4810          24 :     old_acl = DatumGetAclPCopy(oldAclDatum);
    4811             : 
    4812             :     /*
    4813             :      * Generate new ACL.  This usage of aclnewowner is a bit off-label when
    4814             :      * oldroleid isn't the owner; but it does the job fine.
    4815             :      */
    4816          24 :     new_acl = aclnewowner(old_acl, oldroleid, newroleid);
    4817             : 
    4818             :     /*
    4819             :      * If we end with an empty ACL, delete the pg_init_privs entry.  (That
    4820             :      * probably can't happen here, but we may as well cover the case.)
    4821             :      */
    4822          24 :     if (new_acl == NULL || ACL_NUM(new_acl) == 0)
    4823             :     {
    4824           0 :         CatalogTupleDelete(rel, &oldtuple->t_self);
    4825             :     }
    4826             :     else
    4827             :     {
    4828          24 :         Datum       values[Natts_pg_init_privs] = {0};
    4829          24 :         bool        nulls[Natts_pg_init_privs] = {0};
    4830          24 :         bool        replaces[Natts_pg_init_privs] = {0};
    4831             : 
    4832             :         /* Update existing entry. */
    4833          24 :         values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4834          24 :         replaces[Anum_pg_init_privs_initprivs - 1] = true;
    4835             : 
    4836          24 :         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
    4837             :                                      values, nulls, replaces);
    4838          24 :         CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    4839             :     }
    4840             : 
    4841             :     /*
    4842             :      * Update the shared dependency ACL info.
    4843             :      */
    4844          24 :     noldmembers = aclmembers(old_acl, &oldmembers);
    4845          24 :     nnewmembers = aclmembers(new_acl, &newmembers);
    4846             : 
    4847          24 :     updateInitAclDependencies(classid, objid, objsubid,
    4848             :                               noldmembers, oldmembers,
    4849             :                               nnewmembers, newmembers);
    4850             : 
    4851          24 :     systable_endscan(scan);
    4852             : 
    4853             :     /* prevent error when processing objects multiple times */
    4854          24 :     CommandCounterIncrement();
    4855             : 
    4856          24 :     table_close(rel, RowExclusiveLock);
    4857             : }
    4858             : 
    4859             : /*
    4860             :  * RemoveRoleFromInitPriv
    4861             :  *
    4862             :  * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
    4863             :  */
    4864             : void
    4865          28 : RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
    4866             : {
    4867             :     Relation    rel;
    4868             :     ScanKeyData key[3];
    4869             :     SysScanDesc scan;
    4870             :     HeapTuple   oldtuple;
    4871             :     int         cacheid;
    4872             :     HeapTuple   objtuple;
    4873             :     Oid         ownerId;
    4874             :     Datum       oldAclDatum;
    4875             :     bool        isNull;
    4876             :     Acl        *old_acl;
    4877             :     Acl        *new_acl;
    4878             :     HeapTuple   newtuple;
    4879             :     int         noldmembers;
    4880             :     int         nnewmembers;
    4881             :     Oid        *oldmembers;
    4882             :     Oid        *newmembers;
    4883             : 
    4884             :     /* Search for existing pg_init_privs entry for the target object. */
    4885          28 :     rel = table_open(InitPrivsRelationId, RowExclusiveLock);
    4886             : 
    4887          28 :     ScanKeyInit(&key[0],
    4888             :                 Anum_pg_init_privs_objoid,
    4889             :                 BTEqualStrategyNumber, F_OIDEQ,
    4890             :                 ObjectIdGetDatum(objid));
    4891          28 :     ScanKeyInit(&key[1],
    4892             :                 Anum_pg_init_privs_classoid,
    4893             :                 BTEqualStrategyNumber, F_OIDEQ,
    4894             :                 ObjectIdGetDatum(classid));
    4895          28 :     ScanKeyInit(&key[2],
    4896             :                 Anum_pg_init_privs_objsubid,
    4897             :                 BTEqualStrategyNumber, F_INT4EQ,
    4898             :                 Int32GetDatum(objsubid));
    4899             : 
    4900          28 :     scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
    4901             :                               NULL, 3, key);
    4902             : 
    4903             :     /* There should exist only one entry or none. */
    4904          28 :     oldtuple = systable_getnext(scan);
    4905             : 
    4906          28 :     if (!HeapTupleIsValid(oldtuple))
    4907             :     {
    4908             :         /*
    4909             :          * Hmm, why are we here if there's no entry?  But pack up and go away
    4910             :          * quietly.
    4911             :          */
    4912           0 :         systable_endscan(scan);
    4913           0 :         table_close(rel, RowExclusiveLock);
    4914           0 :         return;
    4915             :     }
    4916             : 
    4917             :     /* Get a writable copy of the existing ACL. */
    4918          28 :     oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4919             :                                RelationGetDescr(rel), &isNull);
    4920             :     Assert(!isNull);
    4921          28 :     old_acl = DatumGetAclPCopy(oldAclDatum);
    4922             : 
    4923             :     /*
    4924             :      * We need the members of both old and new ACLs so we can correct the
    4925             :      * shared dependency information.  Collect data before
    4926             :      * merge_acl_with_grant throws away old_acl.
    4927             :      */
    4928          28 :     noldmembers = aclmembers(old_acl, &oldmembers);
    4929             : 
    4930             :     /* Must find out the owner's OID the hard way. */
    4931          28 :     cacheid = get_object_catcache_oid(classid);
    4932          28 :     objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
    4933          28 :     if (!HeapTupleIsValid(objtuple))
    4934           0 :         elog(ERROR, "cache lookup failed for %s %u",
    4935             :              get_object_class_descr(classid), objid);
    4936             : 
    4937          28 :     ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    4938             :                                                       objtuple,
    4939          28 :                                                       get_object_attnum_owner(classid)));
    4940          28 :     ReleaseSysCache(objtuple);
    4941             : 
    4942             :     /*
    4943             :      * Generate new ACL.  Grantor of rights is always the same as the owner.
    4944             :      */
    4945          28 :     if (old_acl != NULL)
    4946          28 :         new_acl = merge_acl_with_grant(old_acl,
    4947             :                                        false,   /* is_grant */
    4948             :                                        false,   /* grant_option */
    4949             :                                        DROP_RESTRICT,
    4950          28 :                                        list_make1_oid(roleid),
    4951             :                                        ACLITEM_ALL_PRIV_BITS,
    4952             :                                        ownerId,
    4953             :                                        ownerId);
    4954             :     else
    4955           0 :         new_acl = NULL;         /* this case shouldn't happen, probably */
    4956             : 
    4957             :     /* If we end with an empty ACL, delete the pg_init_privs entry. */
    4958          28 :     if (new_acl == NULL || ACL_NUM(new_acl) == 0)
    4959             :     {
    4960           0 :         CatalogTupleDelete(rel, &oldtuple->t_self);
    4961             :     }
    4962             :     else
    4963             :     {
    4964          28 :         Datum       values[Natts_pg_init_privs] = {0};
    4965          28 :         bool        nulls[Natts_pg_init_privs] = {0};
    4966          28 :         bool        replaces[Natts_pg_init_privs] = {0};
    4967             : 
    4968             :         /* Update existing entry. */
    4969          28 :         values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4970          28 :         replaces[Anum_pg_init_privs_initprivs - 1] = true;
    4971             : 
    4972          28 :         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
    4973             :                                      values, nulls, replaces);
    4974          28 :         CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    4975             :     }
    4976             : 
    4977             :     /*
    4978             :      * Update the shared dependency ACL info.
    4979             :      */
    4980          28 :     nnewmembers = aclmembers(new_acl, &newmembers);
    4981             : 
    4982          28 :     updateInitAclDependencies(classid, objid, objsubid,
    4983             :                               noldmembers, oldmembers,
    4984             :                               nnewmembers, newmembers);
    4985             : 
    4986          28 :     systable_endscan(scan);
    4987             : 
    4988             :     /* prevent error when processing objects multiple times */
    4989          28 :     CommandCounterIncrement();
    4990             : 
    4991          28 :     table_close(rel, RowExclusiveLock);
    4992             : }

Generated by: LCOV version 1.16