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

Generated by: LCOV version 1.14