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

Generated by: LCOV version 2.0-1