LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 1626 2031 80.1 %
Date: 2019-11-22 07:06:56 Functions: 83 85 97.6 %
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-2019, 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             :  *-------------------------------------------------------------------------
      17             :  */
      18             : #include "postgres.h"
      19             : 
      20             : #include "access/genam.h"
      21             : #include "access/heapam.h"
      22             : #include "access/htup_details.h"
      23             : #include "access/sysattr.h"
      24             : #include "access/tableam.h"
      25             : #include "access/xact.h"
      26             : #include "catalog/binary_upgrade.h"
      27             : #include "catalog/catalog.h"
      28             : #include "catalog/dependency.h"
      29             : #include "catalog/indexing.h"
      30             : #include "catalog/objectaccess.h"
      31             : #include "catalog/pg_aggregate.h"
      32             : #include "catalog/pg_am.h"
      33             : #include "catalog/pg_authid.h"
      34             : #include "catalog/pg_cast.h"
      35             : #include "catalog/pg_collation.h"
      36             : #include "catalog/pg_conversion.h"
      37             : #include "catalog/pg_database.h"
      38             : #include "catalog/pg_default_acl.h"
      39             : #include "catalog/pg_event_trigger.h"
      40             : #include "catalog/pg_extension.h"
      41             : #include "catalog/pg_foreign_data_wrapper.h"
      42             : #include "catalog/pg_foreign_server.h"
      43             : #include "catalog/pg_init_privs.h"
      44             : #include "catalog/pg_language.h"
      45             : #include "catalog/pg_largeobject.h"
      46             : #include "catalog/pg_largeobject_metadata.h"
      47             : #include "catalog/pg_namespace.h"
      48             : #include "catalog/pg_opclass.h"
      49             : #include "catalog/pg_operator.h"
      50             : #include "catalog/pg_opfamily.h"
      51             : #include "catalog/pg_proc.h"
      52             : #include "catalog/pg_statistic_ext.h"
      53             : #include "catalog/pg_subscription.h"
      54             : #include "catalog/pg_tablespace.h"
      55             : #include "catalog/pg_transform.h"
      56             : #include "catalog/pg_ts_config.h"
      57             : #include "catalog/pg_ts_dict.h"
      58             : #include "catalog/pg_ts_parser.h"
      59             : #include "catalog/pg_ts_template.h"
      60             : #include "catalog/pg_type.h"
      61             : #include "commands/dbcommands.h"
      62             : #include "commands/event_trigger.h"
      63             : #include "commands/extension.h"
      64             : #include "commands/proclang.h"
      65             : #include "commands/tablespace.h"
      66             : #include "foreign/foreign.h"
      67             : #include "miscadmin.h"
      68             : #include "nodes/makefuncs.h"
      69             : #include "parser/parse_func.h"
      70             : #include "parser/parse_type.h"
      71             : #include "utils/acl.h"
      72             : #include "utils/aclchk_internal.h"
      73             : #include "utils/builtins.h"
      74             : #include "utils/fmgroids.h"
      75             : #include "utils/lsyscache.h"
      76             : #include "utils/rel.h"
      77             : #include "utils/syscache.h"
      78             : 
      79             : /*
      80             :  * Internal format used by ALTER DEFAULT PRIVILEGES.
      81             :  */
      82             : typedef struct
      83             : {
      84             :     Oid         roleid;         /* owning role */
      85             :     Oid         nspid;          /* namespace, or InvalidOid if none */
      86             :     /* remaining fields are same as in InternalGrant: */
      87             :     bool        is_grant;
      88             :     ObjectType  objtype;
      89             :     bool        all_privs;
      90             :     AclMode     privileges;
      91             :     List       *grantees;
      92             :     bool        grant_option;
      93             :     DropBehavior behavior;
      94             : } InternalDefaultACL;
      95             : 
      96             : /*
      97             :  * When performing a binary-upgrade, pg_dump will call a function to set
      98             :  * this variable to let us know that we need to populate the pg_init_privs
      99             :  * table for the GRANT/REVOKE commands while this variable is set to true.
     100             :  */
     101             : bool        binary_upgrade_record_init_privs = false;
     102             : 
     103             : static void ExecGrantStmt_oids(InternalGrant *istmt);
     104             : static void ExecGrant_Relation(InternalGrant *grantStmt);
     105             : static void ExecGrant_Database(InternalGrant *grantStmt);
     106             : static void ExecGrant_Fdw(InternalGrant *grantStmt);
     107             : static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
     108             : static void ExecGrant_Function(InternalGrant *grantStmt);
     109             : static void ExecGrant_Language(InternalGrant *grantStmt);
     110             : static void ExecGrant_Largeobject(InternalGrant *grantStmt);
     111             : static void ExecGrant_Namespace(InternalGrant *grantStmt);
     112             : static void ExecGrant_Tablespace(InternalGrant *grantStmt);
     113             : static void ExecGrant_Type(InternalGrant *grantStmt);
     114             : 
     115             : static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
     116             : static void SetDefaultACL(InternalDefaultACL *iacls);
     117             : 
     118             : static List *objectNamesToOids(ObjectType objtype, List *objnames);
     119             : static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
     120             : static List *getRelationsInNamespace(Oid namespaceId, char relkind);
     121             : static void expand_col_privileges(List *colnames, Oid table_oid,
     122             :                                   AclMode this_privileges,
     123             :                                   AclMode *col_privileges,
     124             :                                   int num_col_privileges);
     125             : static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
     126             :                                       AclMode this_privileges,
     127             :                                       AclMode *col_privileges,
     128             :                                       int num_col_privileges);
     129             : static AclMode string_to_privilege(const char *privname);
     130             : static const char *privilege_to_string(AclMode privilege);
     131             : static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
     132             :                                         bool all_privs, AclMode privileges,
     133             :                                         Oid objectId, Oid grantorId,
     134             :                                         ObjectType objtype, const char *objname,
     135             :                                         AttrNumber att_number, const char *colname);
     136             : static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum,
     137             :                           Oid roleid, AclMode mask, AclMaskHow how);
     138             : static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
     139             :                                     Acl *new_acl);
     140             : static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
     141             :                                           Acl *new_acl);
     142             : 
     143             : 
     144             : #ifdef ACLDEBUG
     145             : static void
     146             : dumpacl(Acl *acl)
     147             : {
     148             :     int         i;
     149             :     AclItem    *aip;
     150             : 
     151             :     elog(DEBUG2, "acl size = %d, # acls = %d",
     152             :          ACL_SIZE(acl), ACL_NUM(acl));
     153             :     aip = ACL_DAT(acl);
     154             :     for (i = 0; i < ACL_NUM(acl); ++i)
     155             :         elog(DEBUG2, " acl[%d]: %s", i,
     156             :              DatumGetCString(DirectFunctionCall1(aclitemout,
     157             :                                                  PointerGetDatum(aip + i))));
     158             : }
     159             : #endif                          /* ACLDEBUG */
     160             : 
     161             : 
     162             : /*
     163             :  * If is_grant is true, adds the given privileges for the list of
     164             :  * grantees to the existing old_acl.  If is_grant is false, the
     165             :  * privileges for the given grantees are removed from old_acl.
     166             :  *
     167             :  * NB: the original old_acl is pfree'd.
     168             :  */
     169             : static Acl *
     170       84710 : merge_acl_with_grant(Acl *old_acl, bool is_grant,
     171             :                      bool grant_option, DropBehavior behavior,
     172             :                      List *grantees, AclMode privileges,
     173             :                      Oid grantorId, Oid ownerId)
     174             : {
     175             :     unsigned    modechg;
     176             :     ListCell   *j;
     177             :     Acl        *new_acl;
     178             : 
     179       84710 :     modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
     180             : 
     181             : #ifdef ACLDEBUG
     182             :     dumpacl(old_acl);
     183             : #endif
     184       84710 :     new_acl = old_acl;
     185             : 
     186      169464 :     foreach(j, grantees)
     187             :     {
     188             :         AclItem     aclitem;
     189             :         Acl        *newer_acl;
     190             : 
     191       84762 :         aclitem.ai_grantee = lfirst_oid(j);
     192             : 
     193             :         /*
     194             :          * Grant options can only be granted to individual roles, not PUBLIC.
     195             :          * The reason is that if a user would re-grant a privilege that he
     196             :          * held through PUBLIC, and later the user is removed, the situation
     197             :          * is impossible to clean up.
     198             :          */
     199       84762 :         if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
     200           0 :             ereport(ERROR,
     201             :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     202             :                      errmsg("grant options can only be granted to roles")));
     203             : 
     204       84762 :         aclitem.ai_grantor = grantorId;
     205             : 
     206             :         /*
     207             :          * The asymmetry in the conditions here comes from the spec.  In
     208             :          * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
     209             :          * to grant both the basic privilege and its grant option. But in
     210             :          * REVOKE, plain revoke revokes both the basic privilege and its grant
     211             :          * option, while REVOKE GRANT OPTION revokes only the option.
     212             :          */
     213       84762 :         ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
     214             :                                    (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
     215             :                                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
     216             : 
     217       84762 :         newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
     218             : 
     219             :         /* avoid memory leak when there are many grantees */
     220       84754 :         pfree(new_acl);
     221       84754 :         new_acl = newer_acl;
     222             : 
     223             : #ifdef ACLDEBUG
     224             :         dumpacl(new_acl);
     225             : #endif
     226             :     }
     227             : 
     228       84702 :     return new_acl;
     229             : }
     230             : 
     231             : /*
     232             :  * Restrict the privileges to what we can actually grant, and emit
     233             :  * the standards-mandated warning and error messages.
     234             :  */
     235             : static AclMode
     236       84654 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
     237             :                          AclMode privileges, Oid objectId, Oid grantorId,
     238             :                          ObjectType objtype, const char *objname,
     239             :                          AttrNumber att_number, const char *colname)
     240             : {
     241             :     AclMode     this_privileges;
     242             :     AclMode     whole_mask;
     243             : 
     244       84654 :     switch (objtype)
     245             :     {
     246             :         case OBJECT_COLUMN:
     247       45530 :             whole_mask = ACL_ALL_RIGHTS_COLUMN;
     248       45530 :             break;
     249             :         case OBJECT_TABLE:
     250       23174 :             whole_mask = ACL_ALL_RIGHTS_RELATION;
     251       23174 :             break;
     252             :         case OBJECT_SEQUENCE:
     253          94 :             whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
     254          94 :             break;
     255             :         case OBJECT_DATABASE:
     256         684 :             whole_mask = ACL_ALL_RIGHTS_DATABASE;
     257         684 :             break;
     258             :         case OBJECT_FUNCTION:
     259       13890 :             whole_mask = ACL_ALL_RIGHTS_FUNCTION;
     260       13890 :             break;
     261             :         case OBJECT_LANGUAGE:
     262          22 :             whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
     263          22 :             break;
     264             :         case OBJECT_LARGEOBJECT:
     265          38 :             whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
     266          38 :             break;
     267             :         case OBJECT_SCHEMA:
     268        1032 :             whole_mask = ACL_ALL_RIGHTS_SCHEMA;
     269        1032 :             break;
     270             :         case OBJECT_TABLESPACE:
     271           0 :             whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
     272           0 :             break;
     273             :         case OBJECT_FDW:
     274          62 :             whole_mask = ACL_ALL_RIGHTS_FDW;
     275          62 :             break;
     276             :         case OBJECT_FOREIGN_SERVER:
     277          62 :             whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     278          62 :             break;
     279             :         case OBJECT_EVENT_TRIGGER:
     280           0 :             elog(ERROR, "grantable rights not supported for event triggers");
     281             :             /* not reached, but keep compiler quiet */
     282             :             return ACL_NO_RIGHTS;
     283             :         case OBJECT_TYPE:
     284          66 :             whole_mask = ACL_ALL_RIGHTS_TYPE;
     285          66 :             break;
     286             :         default:
     287           0 :             elog(ERROR, "unrecognized object type: %d", objtype);
     288             :             /* not reached, but keep compiler quiet */
     289             :             return ACL_NO_RIGHTS;
     290             :     }
     291             : 
     292             :     /*
     293             :      * If we found no grant options, consider whether to issue a hard error.
     294             :      * Per spec, having any privilege at all on the object will get you by
     295             :      * here.
     296             :      */
     297       84654 :     if (avail_goptions == ACL_NO_RIGHTS)
     298             :     {
     299          44 :         if (pg_aclmask(objtype, objectId, att_number, grantorId,
     300          44 :                        whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
     301             :                        ACLMASK_ANY) == ACL_NO_RIGHTS)
     302             :         {
     303          20 :             if (objtype == OBJECT_COLUMN && colname)
     304           0 :                 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
     305             :             else
     306          20 :                 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
     307             :         }
     308             :     }
     309             : 
     310             :     /*
     311             :      * Restrict the operation to what we can actually grant or revoke, and
     312             :      * issue a warning if appropriate.  (For REVOKE this isn't quite what the
     313             :      * spec says to do: the spec seems to want a warning only if no privilege
     314             :      * bits actually change in the ACL. In practice that behavior seems much
     315             :      * too noisy, as well as inconsistent with the GRANT case.)
     316             :      */
     317       84634 :     this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
     318       84634 :     if (is_grant)
     319             :     {
     320       24766 :         if (this_privileges == 0)
     321             :         {
     322          20 :             if (objtype == OBJECT_COLUMN && colname)
     323           0 :                 ereport(WARNING,
     324             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     325             :                          errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
     326             :                                 colname, objname)));
     327             :             else
     328          20 :                 ereport(WARNING,
     329             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     330             :                          errmsg("no privileges were granted for \"%s\"",
     331             :                                 objname)));
     332             :         }
     333       24746 :         else if (!all_privs && this_privileges != privileges)
     334             :         {
     335           0 :             if (objtype == OBJECT_COLUMN && colname)
     336           0 :                 ereport(WARNING,
     337             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     338             :                          errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
     339             :                                 colname, objname)));
     340             :             else
     341           0 :                 ereport(WARNING,
     342             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     343             :                          errmsg("not all privileges were granted for \"%s\"",
     344             :                                 objname)));
     345             :         }
     346             :     }
     347             :     else
     348             :     {
     349       59868 :         if (this_privileges == 0)
     350             :         {
     351           4 :             if (objtype == OBJECT_COLUMN && colname)
     352           0 :                 ereport(WARNING,
     353             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     354             :                          errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
     355             :                                 colname, objname)));
     356             :             else
     357           4 :                 ereport(WARNING,
     358             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     359             :                          errmsg("no privileges could be revoked for \"%s\"",
     360             :                                 objname)));
     361             :         }
     362       59864 :         else if (!all_privs && this_privileges != privileges)
     363             :         {
     364           0 :             if (objtype == OBJECT_COLUMN && colname)
     365           0 :                 ereport(WARNING,
     366             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     367             :                          errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
     368             :                                 colname, objname)));
     369             :             else
     370           0 :                 ereport(WARNING,
     371             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     372             :                          errmsg("not all privileges could be revoked for \"%s\"",
     373             :                                 objname)));
     374             :         }
     375             :     }
     376             : 
     377       84634 :     return this_privileges;
     378             : }
     379             : 
     380             : /*
     381             :  * Called to execute the utility commands GRANT and REVOKE
     382             :  */
     383             : void
     384       39550 : ExecuteGrantStmt(GrantStmt *stmt)
     385             : {
     386             :     InternalGrant istmt;
     387             :     ListCell   *cell;
     388             :     const char *errormsg;
     389             :     AclMode     all_privileges;
     390             : 
     391             :     /*
     392             :      * Turn the regular GrantStmt into the InternalGrant form.
     393             :      */
     394       39550 :     istmt.is_grant = stmt->is_grant;
     395       39550 :     istmt.objtype = stmt->objtype;
     396             : 
     397             :     /* Collect the OIDs of the target objects */
     398       39550 :     switch (stmt->targtype)
     399             :     {
     400             :         case ACL_TARGET_OBJECT:
     401       39530 :             istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
     402       39514 :             break;
     403             :         case ACL_TARGET_ALL_IN_SCHEMA:
     404          20 :             istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
     405          20 :             break;
     406             :             /* ACL_TARGET_DEFAULTS should not be seen here */
     407             :         default:
     408           0 :             elog(ERROR, "unrecognized GrantStmt.targtype: %d",
     409             :                  (int) stmt->targtype);
     410             :     }
     411             : 
     412             :     /* all_privs to be filled below */
     413             :     /* privileges to be filled below */
     414       39534 :     istmt.col_privs = NIL;      /* may get filled below */
     415       39534 :     istmt.grantees = NIL;       /* filled below */
     416       39534 :     istmt.grant_option = stmt->grant_option;
     417       39534 :     istmt.behavior = stmt->behavior;
     418             : 
     419             :     /*
     420             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
     421             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
     422             :      * there shouldn't be any additional work needed to support this case.
     423             :      */
     424       79104 :     foreach(cell, stmt->grantees)
     425             :     {
     426       39574 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     427             :         Oid         grantee_uid;
     428             : 
     429       39574 :         switch (grantee->roletype)
     430             :         {
     431             :             case ROLESPEC_PUBLIC:
     432       36736 :                 grantee_uid = ACL_ID_PUBLIC;
     433       36736 :                 break;
     434             :             default:
     435        2838 :                 grantee_uid = get_rolespec_oid(grantee, false);
     436        2834 :                 break;
     437             :         }
     438       39570 :         istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
     439             :     }
     440             : 
     441             :     /*
     442             :      * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
     443             :      * bitmask.  Note: objtype can't be OBJECT_COLUMN.
     444             :      */
     445       39530 :     switch (stmt->objtype)
     446             :     {
     447             :         case OBJECT_TABLE:
     448             : 
     449             :             /*
     450             :              * Because this might be a sequence, we test both relation and
     451             :              * sequence bits, and later do a more limited test when we know
     452             :              * the object type.
     453             :              */
     454       23700 :             all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
     455       23700 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     456       23700 :             break;
     457             :         case OBJECT_SEQUENCE:
     458           2 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
     459           2 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
     460           2 :             break;
     461             :         case OBJECT_DATABASE:
     462         680 :             all_privileges = ACL_ALL_RIGHTS_DATABASE;
     463         680 :             errormsg = gettext_noop("invalid privilege type %s for database");
     464         680 :             break;
     465             :         case OBJECT_DOMAIN:
     466          14 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     467          14 :             errormsg = gettext_noop("invalid privilege type %s for domain");
     468          14 :             break;
     469             :         case OBJECT_FUNCTION:
     470       13834 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     471       13834 :             errormsg = gettext_noop("invalid privilege type %s for function");
     472       13834 :             break;
     473             :         case OBJECT_LANGUAGE:
     474          26 :             all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
     475          26 :             errormsg = gettext_noop("invalid privilege type %s for language");
     476          26 :             break;
     477             :         case OBJECT_LARGEOBJECT:
     478          38 :             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
     479          38 :             errormsg = gettext_noop("invalid privilege type %s for large object");
     480          38 :             break;
     481             :         case OBJECT_SCHEMA:
     482        1028 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
     483        1028 :             errormsg = gettext_noop("invalid privilege type %s for schema");
     484        1028 :             break;
     485             :         case OBJECT_PROCEDURE:
     486          28 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     487          28 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
     488          28 :             break;
     489             :         case OBJECT_ROUTINE:
     490           4 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     491           4 :             errormsg = gettext_noop("invalid privilege type %s for routine");
     492           4 :             break;
     493             :         case OBJECT_TABLESPACE:
     494           0 :             all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
     495           0 :             errormsg = gettext_noop("invalid privilege type %s for tablespace");
     496           0 :             break;
     497             :         case OBJECT_TYPE:
     498          60 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     499          60 :             errormsg = gettext_noop("invalid privilege type %s for type");
     500          60 :             break;
     501             :         case OBJECT_FDW:
     502          62 :             all_privileges = ACL_ALL_RIGHTS_FDW;
     503          62 :             errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
     504          62 :             break;
     505             :         case OBJECT_FOREIGN_SERVER:
     506          54 :             all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     507          54 :             errormsg = gettext_noop("invalid privilege type %s for foreign server");
     508          54 :             break;
     509             :         default:
     510           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     511             :                  (int) stmt->objtype);
     512             :             /* keep compiler quiet */
     513             :             all_privileges = ACL_NO_RIGHTS;
     514             :             errormsg = NULL;
     515             :     }
     516             : 
     517       39530 :     if (stmt->privileges == NIL)
     518             :     {
     519        3942 :         istmt.all_privs = true;
     520             : 
     521             :         /*
     522             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
     523             :          * depending on the object type
     524             :          */
     525        3942 :         istmt.privileges = ACL_NO_RIGHTS;
     526             :     }
     527             :     else
     528             :     {
     529       35588 :         istmt.all_privs = false;
     530       35588 :         istmt.privileges = ACL_NO_RIGHTS;
     531             : 
     532       72522 :         foreach(cell, stmt->privileges)
     533             :         {
     534       36950 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
     535             :             AclMode     priv;
     536             : 
     537             :             /*
     538             :              * If it's a column-level specification, we just set it aside in
     539             :              * col_privs for the moment; but insist it's for a relation.
     540             :              */
     541       36950 :             if (privnode->cols)
     542             :             {
     543         494 :                 if (stmt->objtype != OBJECT_TABLE)
     544           0 :                     ereport(ERROR,
     545             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     546             :                              errmsg("column privileges are only valid for relations")));
     547         494 :                 istmt.col_privs = lappend(istmt.col_privs, privnode);
     548         494 :                 continue;
     549             :             }
     550             : 
     551       36456 :             if (privnode->priv_name == NULL) /* parser mistake? */
     552           0 :                 elog(ERROR, "AccessPriv node must specify privilege or columns");
     553       36456 :             priv = string_to_privilege(privnode->priv_name);
     554             : 
     555       36456 :             if (priv & ~((AclMode) all_privileges))
     556          16 :                 ereport(ERROR,
     557             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     558             :                          errmsg(errormsg, privilege_to_string(priv))));
     559             : 
     560       36440 :             istmt.privileges |= priv;
     561             :         }
     562             :     }
     563             : 
     564       39514 :     ExecGrantStmt_oids(&istmt);
     565       39474 : }
     566             : 
     567             : /*
     568             :  * ExecGrantStmt_oids
     569             :  *
     570             :  * Internal entry point for granting and revoking privileges.
     571             :  */
     572             : static void
     573       39546 : ExecGrantStmt_oids(InternalGrant *istmt)
     574             : {
     575       39546 :     switch (istmt->objtype)
     576             :     {
     577             :         case OBJECT_TABLE:
     578             :         case OBJECT_SEQUENCE:
     579       23714 :             ExecGrant_Relation(istmt);
     580       23710 :             break;
     581             :         case OBJECT_DATABASE:
     582         684 :             ExecGrant_Database(istmt);
     583         684 :             break;
     584             :         case OBJECT_DOMAIN:
     585             :         case OBJECT_TYPE:
     586          74 :             ExecGrant_Type(istmt);
     587          62 :             break;
     588             :         case OBJECT_FDW:
     589          62 :             ExecGrant_Fdw(istmt);
     590          50 :             break;
     591             :         case OBJECT_FOREIGN_SERVER:
     592          62 :             ExecGrant_ForeignServer(istmt);
     593          54 :             break;
     594             :         case OBJECT_FUNCTION:
     595             :         case OBJECT_PROCEDURE:
     596             :         case OBJECT_ROUTINE:
     597       13862 :             ExecGrant_Function(istmt);
     598       13862 :             break;
     599             :         case OBJECT_LANGUAGE:
     600          26 :             ExecGrant_Language(istmt);
     601          22 :             break;
     602             :         case OBJECT_LARGEOBJECT:
     603          34 :             ExecGrant_Largeobject(istmt);
     604          34 :             break;
     605             :         case OBJECT_SCHEMA:
     606        1028 :             ExecGrant_Namespace(istmt);
     607        1028 :             break;
     608             :         case OBJECT_TABLESPACE:
     609           0 :             ExecGrant_Tablespace(istmt);
     610           0 :             break;
     611             :         default:
     612           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     613             :                  (int) istmt->objtype);
     614             :     }
     615             : 
     616             :     /*
     617             :      * Pass the info to event triggers about the just-executed GRANT.  Note
     618             :      * that we prefer to do it after actually executing it, because that gives
     619             :      * the functions a chance to adjust the istmt with privileges actually
     620             :      * granted.
     621             :      */
     622       39506 :     if (EventTriggerSupportsObjectType(istmt->objtype))
     623       38822 :         EventTriggerCollectGrant(istmt);
     624       39506 : }
     625             : 
     626             : /*
     627             :  * objectNamesToOids
     628             :  *
     629             :  * Turn a list of object names of a given type into an Oid list.
     630             :  *
     631             :  * XXX: This function doesn't take any sort of locks on the objects whose
     632             :  * names it looks up.  In the face of concurrent DDL, we might easily latch
     633             :  * onto an old version of an object, causing the GRANT or REVOKE statement
     634             :  * to fail.
     635             :  */
     636             : static List *
     637       39530 : objectNamesToOids(ObjectType objtype, List *objnames)
     638             : {
     639       39530 :     List       *objects = NIL;
     640             :     ListCell   *cell;
     641             : 
     642             :     Assert(objnames != NIL);
     643             : 
     644       39530 :     switch (objtype)
     645             :     {
     646             :         case OBJECT_TABLE:
     647             :         case OBJECT_SEQUENCE:
     648       47420 :             foreach(cell, objnames)
     649             :             {
     650       23726 :                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
     651             :                 Oid         relOid;
     652             : 
     653       23726 :                 relOid = RangeVarGetRelid(relvar, NoLock, false);
     654       23726 :                 objects = lappend_oid(objects, relOid);
     655             :             }
     656       23694 :             break;
     657             :         case OBJECT_DATABASE:
     658        1360 :             foreach(cell, objnames)
     659             :             {
     660         680 :                 char       *dbname = strVal(lfirst(cell));
     661             :                 Oid         dbid;
     662             : 
     663         680 :                 dbid = get_database_oid(dbname, false);
     664         680 :                 objects = lappend_oid(objects, dbid);
     665             :             }
     666         680 :             break;
     667             :         case OBJECT_DOMAIN:
     668             :         case OBJECT_TYPE:
     669         148 :             foreach(cell, objnames)
     670             :             {
     671          74 :                 List       *typname = (List *) lfirst(cell);
     672             :                 Oid         oid;
     673             : 
     674          74 :                 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
     675          74 :                 objects = lappend_oid(objects, oid);
     676             :             }
     677          74 :             break;
     678             :         case OBJECT_FUNCTION:
     679       27684 :             foreach(cell, objnames)
     680             :             {
     681       13854 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     682             :                 Oid         funcid;
     683             : 
     684       13854 :                 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
     685       13846 :                 objects = lappend_oid(objects, funcid);
     686             :             }
     687       13830 :             break;
     688             :         case OBJECT_LANGUAGE:
     689          52 :             foreach(cell, objnames)
     690             :             {
     691          26 :                 char       *langname = strVal(lfirst(cell));
     692             :                 Oid         oid;
     693             : 
     694          26 :                 oid = get_language_oid(langname, false);
     695          26 :                 objects = lappend_oid(objects, oid);
     696             :             }
     697          26 :             break;
     698             :         case OBJECT_LARGEOBJECT:
     699          96 :             foreach(cell, objnames)
     700             :             {
     701          54 :                 Oid         lobjOid = oidparse(lfirst(cell));
     702             : 
     703          54 :                 if (!LargeObjectExists(lobjOid))
     704           8 :                     ereport(ERROR,
     705             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
     706             :                              errmsg("large object %u does not exist",
     707             :                                     lobjOid)));
     708             : 
     709          46 :                 objects = lappend_oid(objects, lobjOid);
     710             :             }
     711          42 :             break;
     712             :         case OBJECT_SCHEMA:
     713        2060 :             foreach(cell, objnames)
     714             :             {
     715        1032 :                 char       *nspname = strVal(lfirst(cell));
     716             :                 Oid         oid;
     717             : 
     718        1032 :                 oid = get_namespace_oid(nspname, false);
     719        1032 :                 objects = lappend_oid(objects, oid);
     720             :             }
     721        1028 :             break;
     722             :         case OBJECT_PROCEDURE:
     723          48 :             foreach(cell, objnames)
     724             :             {
     725          24 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     726             :                 Oid         procid;
     727             : 
     728          24 :                 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
     729          24 :                 objects = lappend_oid(objects, procid);
     730             :             }
     731          24 :             break;
     732             :         case OBJECT_ROUTINE:
     733           0 :             foreach(cell, objnames)
     734             :             {
     735           0 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     736             :                 Oid         routid;
     737             : 
     738           0 :                 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
     739           0 :                 objects = lappend_oid(objects, routid);
     740             :             }
     741           0 :             break;
     742             :         case OBJECT_TABLESPACE:
     743           0 :             foreach(cell, objnames)
     744             :             {
     745           0 :                 char       *spcname = strVal(lfirst(cell));
     746             :                 Oid         spcoid;
     747             : 
     748           0 :                 spcoid = get_tablespace_oid(spcname, false);
     749           0 :                 objects = lappend_oid(objects, spcoid);
     750             :             }
     751           0 :             break;
     752             :         case OBJECT_FDW:
     753         124 :             foreach(cell, objnames)
     754             :             {
     755          62 :                 char       *fdwname = strVal(lfirst(cell));
     756          62 :                 Oid         fdwid = get_foreign_data_wrapper_oid(fdwname, false);
     757             : 
     758          62 :                 objects = lappend_oid(objects, fdwid);
     759             :             }
     760          62 :             break;
     761             :         case OBJECT_FOREIGN_SERVER:
     762         108 :             foreach(cell, objnames)
     763             :             {
     764          54 :                 char       *srvname = strVal(lfirst(cell));
     765          54 :                 Oid         srvid = get_foreign_server_oid(srvname, false);
     766             : 
     767          54 :                 objects = lappend_oid(objects, srvid);
     768             :             }
     769          54 :             break;
     770             :         default:
     771           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     772             :                  (int) objtype);
     773             :     }
     774             : 
     775       39514 :     return objects;
     776             : }
     777             : 
     778             : /*
     779             :  * objectsInSchemaToOids
     780             :  *
     781             :  * Find all objects of a given type in specified schemas, and make a list
     782             :  * of their Oids.  We check USAGE privilege on the schemas, but there is
     783             :  * no privilege checking on the individual objects here.
     784             :  */
     785             : static List *
     786          20 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
     787             : {
     788          20 :     List       *objects = NIL;
     789             :     ListCell   *cell;
     790             : 
     791          40 :     foreach(cell, nspnames)
     792             :     {
     793          20 :         char       *nspname = strVal(lfirst(cell));
     794             :         Oid         namespaceId;
     795             :         List       *objs;
     796             : 
     797          20 :         namespaceId = LookupExplicitNamespace(nspname, false);
     798             : 
     799          20 :         switch (objtype)
     800             :         {
     801             :             case OBJECT_TABLE:
     802           8 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
     803           8 :                 objects = list_concat(objects, objs);
     804           8 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
     805           8 :                 objects = list_concat(objects, objs);
     806           8 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
     807           8 :                 objects = list_concat(objects, objs);
     808           8 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
     809           8 :                 objects = list_concat(objects, objs);
     810           8 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
     811           8 :                 objects = list_concat(objects, objs);
     812           8 :                 break;
     813             :             case OBJECT_SEQUENCE:
     814           0 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
     815           0 :                 objects = list_concat(objects, objs);
     816           0 :                 break;
     817             :             case OBJECT_FUNCTION:
     818             :             case OBJECT_PROCEDURE:
     819             :             case OBJECT_ROUTINE:
     820             :                 {
     821             :                     ScanKeyData key[2];
     822             :                     int         keycount;
     823             :                     Relation    rel;
     824             :                     TableScanDesc scan;
     825             :                     HeapTuple   tuple;
     826             : 
     827          12 :                     keycount = 0;
     828          12 :                     ScanKeyInit(&key[keycount++],
     829             :                                 Anum_pg_proc_pronamespace,
     830             :                                 BTEqualStrategyNumber, F_OIDEQ,
     831             :                                 ObjectIdGetDatum(namespaceId));
     832             : 
     833          12 :                     if (objtype == OBJECT_FUNCTION)
     834             :                         /* includes aggregates and window functions */
     835           4 :                         ScanKeyInit(&key[keycount++],
     836             :                                     Anum_pg_proc_prokind,
     837             :                                     BTEqualStrategyNumber, F_CHARNE,
     838             :                                     CharGetDatum(PROKIND_PROCEDURE));
     839           8 :                     else if (objtype == OBJECT_PROCEDURE)
     840           4 :                         ScanKeyInit(&key[keycount++],
     841             :                                     Anum_pg_proc_prokind,
     842             :                                     BTEqualStrategyNumber, F_CHAREQ,
     843             :                                     CharGetDatum(PROKIND_PROCEDURE));
     844             : 
     845          12 :                     rel = table_open(ProcedureRelationId, AccessShareLock);
     846          12 :                     scan = table_beginscan_catalog(rel, keycount, key);
     847             : 
     848          48 :                     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     849             :                     {
     850          24 :                         Oid         oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
     851             : 
     852          24 :                         objects = lappend_oid(objects, oid);
     853             :                     }
     854             : 
     855          12 :                     table_endscan(scan);
     856          12 :                     table_close(rel, AccessShareLock);
     857             :                 }
     858          12 :                 break;
     859             :             default:
     860             :                 /* should not happen */
     861           0 :                 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     862             :                      (int) objtype);
     863             :         }
     864             :     }
     865             : 
     866          20 :     return objects;
     867             : }
     868             : 
     869             : /*
     870             :  * getRelationsInNamespace
     871             :  *
     872             :  * Return Oid list of relations in given namespace filtered by relation kind
     873             :  */
     874             : static List *
     875          40 : getRelationsInNamespace(Oid namespaceId, char relkind)
     876             : {
     877          40 :     List       *relations = NIL;
     878             :     ScanKeyData key[2];
     879             :     Relation    rel;
     880             :     TableScanDesc scan;
     881             :     HeapTuple   tuple;
     882             : 
     883          40 :     ScanKeyInit(&key[0],
     884             :                 Anum_pg_class_relnamespace,
     885             :                 BTEqualStrategyNumber, F_OIDEQ,
     886             :                 ObjectIdGetDatum(namespaceId));
     887          40 :     ScanKeyInit(&key[1],
     888             :                 Anum_pg_class_relkind,
     889             :                 BTEqualStrategyNumber, F_CHAREQ,
     890             :                 CharGetDatum(relkind));
     891             : 
     892          40 :     rel = table_open(RelationRelationId, AccessShareLock);
     893          40 :     scan = table_beginscan_catalog(rel, 2, key);
     894             : 
     895          96 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     896             :     {
     897          16 :         Oid         oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
     898             : 
     899          16 :         relations = lappend_oid(relations, oid);
     900             :     }
     901             : 
     902          40 :     table_endscan(scan);
     903          40 :     table_close(rel, AccessShareLock);
     904             : 
     905          40 :     return relations;
     906             : }
     907             : 
     908             : 
     909             : /*
     910             :  * ALTER DEFAULT PRIVILEGES statement
     911             :  */
     912             : void
     913          80 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
     914             : {
     915          80 :     GrantStmt  *action = stmt->action;
     916             :     InternalDefaultACL iacls;
     917             :     ListCell   *cell;
     918          80 :     List       *rolespecs = NIL;
     919          80 :     List       *nspnames = NIL;
     920          80 :     DefElem    *drolespecs = NULL;
     921          80 :     DefElem    *dnspnames = NULL;
     922             :     AclMode     all_privileges;
     923             :     const char *errormsg;
     924             : 
     925             :     /* Deconstruct the "options" part of the statement */
     926         154 :     foreach(cell, stmt->options)
     927             :     {
     928          74 :         DefElem    *defel = (DefElem *) lfirst(cell);
     929             : 
     930          74 :         if (strcmp(defel->defname, "schemas") == 0)
     931             :         {
     932          36 :             if (dnspnames)
     933           0 :                 ereport(ERROR,
     934             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     935             :                          errmsg("conflicting or redundant options"),
     936             :                          parser_errposition(pstate, defel->location)));
     937          36 :             dnspnames = defel;
     938             :         }
     939          38 :         else if (strcmp(defel->defname, "roles") == 0)
     940             :         {
     941          38 :             if (drolespecs)
     942           0 :                 ereport(ERROR,
     943             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     944             :                          errmsg("conflicting or redundant options"),
     945             :                          parser_errposition(pstate, defel->location)));
     946          38 :             drolespecs = defel;
     947             :         }
     948             :         else
     949           0 :             elog(ERROR, "option \"%s\" not recognized", defel->defname);
     950             :     }
     951             : 
     952          80 :     if (dnspnames)
     953          36 :         nspnames = (List *) dnspnames->arg;
     954          80 :     if (drolespecs)
     955          38 :         rolespecs = (List *) drolespecs->arg;
     956             : 
     957             :     /* Prepare the InternalDefaultACL representation of the statement */
     958             :     /* roleid to be filled below */
     959             :     /* nspid to be filled in SetDefaultACLsInSchemas */
     960          80 :     iacls.is_grant = action->is_grant;
     961          80 :     iacls.objtype = action->objtype;
     962             :     /* all_privs to be filled below */
     963             :     /* privileges to be filled below */
     964          80 :     iacls.grantees = NIL;       /* filled below */
     965          80 :     iacls.grant_option = action->grant_option;
     966          80 :     iacls.behavior = action->behavior;
     967             : 
     968             :     /*
     969             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
     970             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
     971             :      * there shouldn't be any additional work needed to support this case.
     972             :      */
     973         160 :     foreach(cell, action->grantees)
     974             :     {
     975          80 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     976             :         Oid         grantee_uid;
     977             : 
     978          80 :         switch (grantee->roletype)
     979             :         {
     980             :             case ROLESPEC_PUBLIC:
     981          24 :                 grantee_uid = ACL_ID_PUBLIC;
     982          24 :                 break;
     983             :             default:
     984          56 :                 grantee_uid = get_rolespec_oid(grantee, false);
     985          56 :                 break;
     986             :         }
     987          80 :         iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
     988             :     }
     989             : 
     990             :     /*
     991             :      * Convert action->privileges, a list of privilege strings, into an
     992             :      * AclMode bitmask.
     993             :      */
     994          80 :     switch (action->objtype)
     995             :     {
     996             :         case OBJECT_TABLE:
     997          42 :             all_privileges = ACL_ALL_RIGHTS_RELATION;
     998          42 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     999          42 :             break;
    1000             :         case OBJECT_SEQUENCE:
    1001           0 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1002           0 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
    1003           0 :             break;
    1004             :         case OBJECT_FUNCTION:
    1005          10 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1006          10 :             errormsg = gettext_noop("invalid privilege type %s for function");
    1007          10 :             break;
    1008             :         case OBJECT_PROCEDURE:
    1009           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1010           0 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
    1011           0 :             break;
    1012             :         case OBJECT_ROUTINE:
    1013           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1014           0 :             errormsg = gettext_noop("invalid privilege type %s for routine");
    1015           0 :             break;
    1016             :         case OBJECT_TYPE:
    1017           8 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
    1018           8 :             errormsg = gettext_noop("invalid privilege type %s for type");
    1019           8 :             break;
    1020             :         case OBJECT_SCHEMA:
    1021          20 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1022          20 :             errormsg = gettext_noop("invalid privilege type %s for schema");
    1023          20 :             break;
    1024             :         default:
    1025           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
    1026             :                  (int) action->objtype);
    1027             :             /* keep compiler quiet */
    1028             :             all_privileges = ACL_NO_RIGHTS;
    1029             :             errormsg = NULL;
    1030             :     }
    1031             : 
    1032          80 :     if (action->privileges == NIL)
    1033             :     {
    1034          18 :         iacls.all_privs = true;
    1035             : 
    1036             :         /*
    1037             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
    1038             :          * depending on the object type
    1039             :          */
    1040          18 :         iacls.privileges = ACL_NO_RIGHTS;
    1041             :     }
    1042             :     else
    1043             :     {
    1044          62 :         iacls.all_privs = false;
    1045          62 :         iacls.privileges = ACL_NO_RIGHTS;
    1046             : 
    1047         124 :         foreach(cell, action->privileges)
    1048             :         {
    1049          62 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
    1050             :             AclMode     priv;
    1051             : 
    1052          62 :             if (privnode->cols)
    1053           0 :                 ereport(ERROR,
    1054             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1055             :                          errmsg("default privileges cannot be set for columns")));
    1056             : 
    1057          62 :             if (privnode->priv_name == NULL) /* parser mistake? */
    1058           0 :                 elog(ERROR, "AccessPriv node must specify privilege");
    1059          62 :             priv = string_to_privilege(privnode->priv_name);
    1060             : 
    1061          62 :             if (priv & ~((AclMode) all_privileges))
    1062           0 :                 ereport(ERROR,
    1063             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1064             :                          errmsg(errormsg, privilege_to_string(priv))));
    1065             : 
    1066          62 :             iacls.privileges |= priv;
    1067             :         }
    1068             :     }
    1069             : 
    1070          80 :     if (rolespecs == NIL)
    1071             :     {
    1072             :         /* Set permissions for myself */
    1073          42 :         iacls.roleid = GetUserId();
    1074             : 
    1075          42 :         SetDefaultACLsInSchemas(&iacls, nspnames);
    1076             :     }
    1077             :     else
    1078             :     {
    1079             :         /* Look up the role OIDs and do permissions checks */
    1080             :         ListCell   *rolecell;
    1081             : 
    1082          76 :         foreach(rolecell, rolespecs)
    1083             :         {
    1084          38 :             RoleSpec   *rolespec = lfirst(rolecell);
    1085             : 
    1086          38 :             iacls.roleid = get_rolespec_oid(rolespec, false);
    1087             : 
    1088             :             /*
    1089             :              * We insist that calling user be a member of each target role. If
    1090             :              * he has that, he could become that role anyway via SET ROLE, so
    1091             :              * FOR ROLE is just a syntactic convenience and doesn't give any
    1092             :              * special privileges.
    1093             :              */
    1094          38 :             check_is_member_of_role(GetUserId(), iacls.roleid);
    1095             : 
    1096          38 :             SetDefaultACLsInSchemas(&iacls, nspnames);
    1097             :         }
    1098             :     }
    1099          76 : }
    1100             : 
    1101             : /*
    1102             :  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
    1103             :  *
    1104             :  * All fields of *iacls except nspid were filled already
    1105             :  */
    1106             : static void
    1107          80 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
    1108             : {
    1109          80 :     if (nspnames == NIL)
    1110             :     {
    1111             :         /* Set database-wide permissions if no schema was specified */
    1112          44 :         iacls->nspid = InvalidOid;
    1113             : 
    1114          44 :         SetDefaultACL(iacls);
    1115             :     }
    1116             :     else
    1117             :     {
    1118             :         /* Look up the schema OIDs and set permissions for each one */
    1119             :         ListCell   *nspcell;
    1120             : 
    1121          68 :         foreach(nspcell, nspnames)
    1122             :         {
    1123          36 :             char       *nspname = strVal(lfirst(nspcell));
    1124             : 
    1125          36 :             iacls->nspid = get_namespace_oid(nspname, false);
    1126             : 
    1127             :             /*
    1128             :              * We used to insist that the target role have CREATE privileges
    1129             :              * on the schema, since without that it wouldn't be able to create
    1130             :              * an object for which these default privileges would apply.
    1131             :              * However, this check proved to be more confusing than helpful,
    1132             :              * and it also caused certain database states to not be
    1133             :              * dumpable/restorable, since revoking CREATE doesn't cause
    1134             :              * default privileges for the schema to go away.  So now, we just
    1135             :              * allow the ALTER; if the user lacks CREATE he'll find out when
    1136             :              * he tries to create an object.
    1137             :              */
    1138             : 
    1139          36 :             SetDefaultACL(iacls);
    1140             :         }
    1141             :     }
    1142          76 : }
    1143             : 
    1144             : 
    1145             : /*
    1146             :  * Create or update a pg_default_acl entry
    1147             :  */
    1148             : static void
    1149          80 : SetDefaultACL(InternalDefaultACL *iacls)
    1150             : {
    1151          80 :     AclMode     this_privileges = iacls->privileges;
    1152             :     char        objtype;
    1153             :     Relation    rel;
    1154             :     HeapTuple   tuple;
    1155             :     bool        isNew;
    1156             :     Acl        *def_acl;
    1157             :     Acl        *old_acl;
    1158             :     Acl        *new_acl;
    1159             :     HeapTuple   newtuple;
    1160             :     Datum       values[Natts_pg_default_acl];
    1161             :     bool        nulls[Natts_pg_default_acl];
    1162             :     bool        replaces[Natts_pg_default_acl];
    1163             :     int         noldmembers;
    1164             :     int         nnewmembers;
    1165             :     Oid        *oldmembers;
    1166             :     Oid        *newmembers;
    1167             : 
    1168          80 :     rel = table_open(DefaultAclRelationId, RowExclusiveLock);
    1169             : 
    1170             :     /*
    1171             :      * The default for a global entry is the hard-wired default ACL for the
    1172             :      * particular object type.  The default for non-global entries is an empty
    1173             :      * ACL.  This must be so because global entries replace the hard-wired
    1174             :      * defaults, while others are added on.
    1175             :      */
    1176          80 :     if (!OidIsValid(iacls->nspid))
    1177          44 :         def_acl = acldefault(iacls->objtype, iacls->roleid);
    1178             :     else
    1179          36 :         def_acl = make_empty_acl();
    1180             : 
    1181             :     /*
    1182             :      * Convert ACL object type to pg_default_acl object type and handle
    1183             :      * all_privs option
    1184             :      */
    1185          80 :     switch (iacls->objtype)
    1186             :     {
    1187             :         case OBJECT_TABLE:
    1188          42 :             objtype = DEFACLOBJ_RELATION;
    1189          42 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1190          10 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1191          42 :             break;
    1192             : 
    1193             :         case OBJECT_SEQUENCE:
    1194           0 :             objtype = DEFACLOBJ_SEQUENCE;
    1195           0 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1196           0 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1197           0 :             break;
    1198             : 
    1199             :         case OBJECT_FUNCTION:
    1200          10 :             objtype = DEFACLOBJ_FUNCTION;
    1201          10 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1202           0 :                 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1203          10 :             break;
    1204             : 
    1205             :         case OBJECT_TYPE:
    1206           8 :             objtype = DEFACLOBJ_TYPE;
    1207           8 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1208           0 :                 this_privileges = ACL_ALL_RIGHTS_TYPE;
    1209           8 :             break;
    1210             : 
    1211             :         case OBJECT_SCHEMA:
    1212          20 :             if (OidIsValid(iacls->nspid))
    1213           4 :                 ereport(ERROR,
    1214             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1215             :                          errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
    1216          16 :             objtype = DEFACLOBJ_NAMESPACE;
    1217          16 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1218           8 :                 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1219          16 :             break;
    1220             : 
    1221             :         default:
    1222           0 :             elog(ERROR, "unrecognized objtype: %d",
    1223             :                  (int) iacls->objtype);
    1224             :             objtype = 0;        /* keep compiler quiet */
    1225             :             break;
    1226             :     }
    1227             : 
    1228             :     /* Search for existing row for this object type in catalog */
    1229         228 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    1230          76 :                             ObjectIdGetDatum(iacls->roleid),
    1231          76 :                             ObjectIdGetDatum(iacls->nspid),
    1232             :                             CharGetDatum(objtype));
    1233             : 
    1234          76 :     if (HeapTupleIsValid(tuple))
    1235             :     {
    1236             :         Datum       aclDatum;
    1237             :         bool        isNull;
    1238             : 
    1239          20 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    1240             :                                    Anum_pg_default_acl_defaclacl,
    1241             :                                    &isNull);
    1242          20 :         if (!isNull)
    1243          20 :             old_acl = DatumGetAclPCopy(aclDatum);
    1244             :         else
    1245           0 :             old_acl = NULL;     /* this case shouldn't happen, probably */
    1246          20 :         isNew = false;
    1247             :     }
    1248             :     else
    1249             :     {
    1250          56 :         old_acl = NULL;
    1251          56 :         isNew = true;
    1252             :     }
    1253             : 
    1254          76 :     if (old_acl != NULL)
    1255             :     {
    1256             :         /*
    1257             :          * We need the members of both old and new ACLs so we can correct the
    1258             :          * shared dependency information.  Collect data before
    1259             :          * merge_acl_with_grant throws away old_acl.
    1260             :          */
    1261          20 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1262             :     }
    1263             :     else
    1264             :     {
    1265             :         /* If no or null entry, start with the default ACL value */
    1266          56 :         old_acl = aclcopy(def_acl);
    1267             :         /* There are no old member roles according to the catalogs */
    1268          56 :         noldmembers = 0;
    1269          56 :         oldmembers = NULL;
    1270             :     }
    1271             : 
    1272             :     /*
    1273             :      * Generate new ACL.  Grantor of rights is always the same as the target
    1274             :      * role.
    1275             :      */
    1276         228 :     new_acl = merge_acl_with_grant(old_acl,
    1277          76 :                                    iacls->is_grant,
    1278          76 :                                    iacls->grant_option,
    1279             :                                    iacls->behavior,
    1280             :                                    iacls->grantees,
    1281             :                                    this_privileges,
    1282             :                                    iacls->roleid,
    1283             :                                    iacls->roleid);
    1284             : 
    1285             :     /*
    1286             :      * If the result is the same as the default value, we do not need an
    1287             :      * explicit pg_default_acl entry, and should in fact remove the entry if
    1288             :      * it exists.  Must sort both arrays to compare properly.
    1289             :      */
    1290          76 :     aclitemsort(new_acl);
    1291          76 :     aclitemsort(def_acl);
    1292          76 :     if (aclequal(new_acl, def_acl))
    1293             :     {
    1294             :         /* delete old entry, if indeed there is one */
    1295          14 :         if (!isNew)
    1296             :         {
    1297             :             ObjectAddress myself;
    1298             : 
    1299             :             /*
    1300             :              * The dependency machinery will take care of removing all
    1301             :              * associated dependency entries.  We use DROP_RESTRICT since
    1302             :              * there shouldn't be anything depending on this entry.
    1303             :              */
    1304          12 :             myself.classId = DefaultAclRelationId;
    1305          12 :             myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1306          12 :             myself.objectSubId = 0;
    1307             : 
    1308          12 :             performDeletion(&myself, DROP_RESTRICT, 0);
    1309             :         }
    1310             :     }
    1311             :     else
    1312             :     {
    1313             :         Oid         defAclOid;
    1314             : 
    1315             :         /* Prepare to insert or update pg_default_acl entry */
    1316          62 :         MemSet(values, 0, sizeof(values));
    1317          62 :         MemSet(nulls, false, sizeof(nulls));
    1318          62 :         MemSet(replaces, false, sizeof(replaces));
    1319             : 
    1320          62 :         if (isNew)
    1321             :         {
    1322             :             /* insert new entry */
    1323          54 :             defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
    1324             :                                            Anum_pg_default_acl_oid);
    1325          54 :             values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
    1326          54 :             values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
    1327          54 :             values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
    1328          54 :             values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
    1329          54 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1330             : 
    1331          54 :             newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
    1332          54 :             CatalogTupleInsert(rel, newtuple);
    1333             :         }
    1334             :         else
    1335             :         {
    1336           8 :             defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1337             : 
    1338             :             /* update existing entry */
    1339           8 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1340           8 :             replaces[Anum_pg_default_acl_defaclacl - 1] = true;
    1341             : 
    1342           8 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
    1343             :                                          values, nulls, replaces);
    1344           8 :             CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    1345             :         }
    1346             : 
    1347             :         /* these dependencies don't change in an update */
    1348          62 :         if (isNew)
    1349             :         {
    1350             :             /* dependency on role */
    1351          54 :             recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
    1352             :                                     iacls->roleid);
    1353             : 
    1354             :             /* dependency on namespace */
    1355          54 :             if (OidIsValid(iacls->nspid))
    1356             :             {
    1357             :                 ObjectAddress myself,
    1358             :                             referenced;
    1359             : 
    1360          22 :                 myself.classId = DefaultAclRelationId;
    1361          22 :                 myself.objectId = defAclOid;
    1362          22 :                 myself.objectSubId = 0;
    1363             : 
    1364          22 :                 referenced.classId = NamespaceRelationId;
    1365          22 :                 referenced.objectId = iacls->nspid;
    1366          22 :                 referenced.objectSubId = 0;
    1367             : 
    1368          22 :                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
    1369             :             }
    1370             :         }
    1371             : 
    1372             :         /*
    1373             :          * Update the shared dependency ACL info
    1374             :          */
    1375          62 :         nnewmembers = aclmembers(new_acl, &newmembers);
    1376             : 
    1377          62 :         updateAclDependencies(DefaultAclRelationId,
    1378             :                               defAclOid, 0,
    1379             :                               iacls->roleid,
    1380             :                               noldmembers, oldmembers,
    1381             :                               nnewmembers, newmembers);
    1382             : 
    1383          62 :         if (isNew)
    1384          54 :             InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
    1385             :         else
    1386           8 :             InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
    1387             :     }
    1388             : 
    1389          76 :     if (HeapTupleIsValid(tuple))
    1390          20 :         ReleaseSysCache(tuple);
    1391             : 
    1392          76 :     table_close(rel, RowExclusiveLock);
    1393          76 : }
    1394             : 
    1395             : 
    1396             : /*
    1397             :  * RemoveRoleFromObjectACL
    1398             :  *
    1399             :  * Used by shdepDropOwned to remove mentions of a role in ACLs
    1400             :  */
    1401             : void
    1402          32 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
    1403             : {
    1404          32 :     if (classid == DefaultAclRelationId)
    1405             :     {
    1406             :         InternalDefaultACL iacls;
    1407             :         Form_pg_default_acl pg_default_acl_tuple;
    1408             :         Relation    rel;
    1409             :         ScanKeyData skey[1];
    1410             :         SysScanDesc scan;
    1411             :         HeapTuple   tuple;
    1412             : 
    1413             :         /* first fetch info needed by SetDefaultACL */
    1414           0 :         rel = table_open(DefaultAclRelationId, AccessShareLock);
    1415             : 
    1416           0 :         ScanKeyInit(&skey[0],
    1417             :                     Anum_pg_default_acl_oid,
    1418             :                     BTEqualStrategyNumber, F_OIDEQ,
    1419             :                     ObjectIdGetDatum(objid));
    1420             : 
    1421           0 :         scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
    1422             :                                   NULL, 1, skey);
    1423             : 
    1424           0 :         tuple = systable_getnext(scan);
    1425             : 
    1426           0 :         if (!HeapTupleIsValid(tuple))
    1427           0 :             elog(ERROR, "could not find tuple for default ACL %u", objid);
    1428             : 
    1429           0 :         pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
    1430             : 
    1431           0 :         iacls.roleid = pg_default_acl_tuple->defaclrole;
    1432           0 :         iacls.nspid = pg_default_acl_tuple->defaclnamespace;
    1433             : 
    1434           0 :         switch (pg_default_acl_tuple->defaclobjtype)
    1435             :         {
    1436             :             case DEFACLOBJ_RELATION:
    1437           0 :                 iacls.objtype = OBJECT_TABLE;
    1438           0 :                 break;
    1439             :             case DEFACLOBJ_SEQUENCE:
    1440           0 :                 iacls.objtype = OBJECT_SEQUENCE;
    1441           0 :                 break;
    1442             :             case DEFACLOBJ_FUNCTION:
    1443           0 :                 iacls.objtype = OBJECT_FUNCTION;
    1444           0 :                 break;
    1445             :             case DEFACLOBJ_TYPE:
    1446           0 :                 iacls.objtype = OBJECT_TYPE;
    1447           0 :                 break;
    1448             :             case DEFACLOBJ_NAMESPACE:
    1449           0 :                 iacls.objtype = OBJECT_SCHEMA;
    1450           0 :                 break;
    1451             :             default:
    1452             :                 /* Shouldn't get here */
    1453           0 :                 elog(ERROR, "unexpected default ACL type: %d",
    1454             :                      (int) pg_default_acl_tuple->defaclobjtype);
    1455             :                 break;
    1456             :         }
    1457             : 
    1458           0 :         systable_endscan(scan);
    1459           0 :         table_close(rel, AccessShareLock);
    1460             : 
    1461           0 :         iacls.is_grant = false;
    1462           0 :         iacls.all_privs = true;
    1463           0 :         iacls.privileges = ACL_NO_RIGHTS;
    1464           0 :         iacls.grantees = list_make1_oid(roleid);
    1465           0 :         iacls.grant_option = false;
    1466           0 :         iacls.behavior = DROP_CASCADE;
    1467             : 
    1468             :         /* Do it */
    1469           0 :         SetDefaultACL(&iacls);
    1470             :     }
    1471             :     else
    1472             :     {
    1473             :         InternalGrant istmt;
    1474             : 
    1475          32 :         switch (classid)
    1476             :         {
    1477             :             case RelationRelationId:
    1478             :                 /* it's OK to use TABLE for a sequence */
    1479          12 :                 istmt.objtype = OBJECT_TABLE;
    1480          12 :                 break;
    1481             :             case DatabaseRelationId:
    1482           4 :                 istmt.objtype = OBJECT_DATABASE;
    1483           4 :                 break;
    1484             :             case TypeRelationId:
    1485           0 :                 istmt.objtype = OBJECT_TYPE;
    1486           0 :                 break;
    1487             :             case ProcedureRelationId:
    1488           8 :                 istmt.objtype = OBJECT_ROUTINE;
    1489           8 :                 break;
    1490             :             case LanguageRelationId:
    1491           0 :                 istmt.objtype = OBJECT_LANGUAGE;
    1492           0 :                 break;
    1493             :             case LargeObjectRelationId:
    1494           0 :                 istmt.objtype = OBJECT_LARGEOBJECT;
    1495           0 :                 break;
    1496             :             case NamespaceRelationId:
    1497           0 :                 istmt.objtype = OBJECT_SCHEMA;
    1498           0 :                 break;
    1499             :             case TableSpaceRelationId:
    1500           0 :                 istmt.objtype = OBJECT_TABLESPACE;
    1501           0 :                 break;
    1502             :             case ForeignServerRelationId:
    1503           8 :                 istmt.objtype = OBJECT_FOREIGN_SERVER;
    1504           8 :                 break;
    1505             :             case ForeignDataWrapperRelationId:
    1506           0 :                 istmt.objtype = OBJECT_FDW;
    1507           0 :                 break;
    1508             :             default:
    1509           0 :                 elog(ERROR, "unexpected object class %u", classid);
    1510             :                 break;
    1511             :         }
    1512          32 :         istmt.is_grant = false;
    1513          32 :         istmt.objects = list_make1_oid(objid);
    1514          32 :         istmt.all_privs = true;
    1515          32 :         istmt.privileges = ACL_NO_RIGHTS;
    1516          32 :         istmt.col_privs = NIL;
    1517          32 :         istmt.grantees = list_make1_oid(roleid);
    1518          32 :         istmt.grant_option = false;
    1519          32 :         istmt.behavior = DROP_CASCADE;
    1520             : 
    1521          32 :         ExecGrantStmt_oids(&istmt);
    1522             :     }
    1523          32 : }
    1524             : 
    1525             : 
    1526             : /*
    1527             :  * Remove a pg_default_acl entry
    1528             :  */
    1529             : void
    1530          48 : RemoveDefaultACLById(Oid defaclOid)
    1531             : {
    1532             :     Relation    rel;
    1533             :     ScanKeyData skey[1];
    1534             :     SysScanDesc scan;
    1535             :     HeapTuple   tuple;
    1536             : 
    1537          48 :     rel = table_open(DefaultAclRelationId, RowExclusiveLock);
    1538             : 
    1539          48 :     ScanKeyInit(&skey[0],
    1540             :                 Anum_pg_default_acl_oid,
    1541             :                 BTEqualStrategyNumber, F_OIDEQ,
    1542             :                 ObjectIdGetDatum(defaclOid));
    1543             : 
    1544          48 :     scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
    1545             :                               NULL, 1, skey);
    1546             : 
    1547          48 :     tuple = systable_getnext(scan);
    1548             : 
    1549          48 :     if (!HeapTupleIsValid(tuple))
    1550           0 :         elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
    1551             : 
    1552          48 :     CatalogTupleDelete(rel, &tuple->t_self);
    1553             : 
    1554          48 :     systable_endscan(scan);
    1555          48 :     table_close(rel, RowExclusiveLock);
    1556          48 : }
    1557             : 
    1558             : 
    1559             : /*
    1560             :  * expand_col_privileges
    1561             :  *
    1562             :  * OR the specified privilege(s) into per-column array entries for each
    1563             :  * specified attribute.  The per-column array is indexed starting at
    1564             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1565             :  */
    1566             : static void
    1567         494 : expand_col_privileges(List *colnames, Oid table_oid,
    1568             :                       AclMode this_privileges,
    1569             :                       AclMode *col_privileges,
    1570             :                       int num_col_privileges)
    1571             : {
    1572             :     ListCell   *cell;
    1573             : 
    1574        2744 :     foreach(cell, colnames)
    1575             :     {
    1576        2250 :         char       *colname = strVal(lfirst(cell));
    1577             :         AttrNumber  attnum;
    1578             : 
    1579        2250 :         attnum = get_attnum(table_oid, colname);
    1580        2250 :         if (attnum == InvalidAttrNumber)
    1581           0 :             ereport(ERROR,
    1582             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1583             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    1584             :                             colname, get_rel_name(table_oid))));
    1585        2250 :         attnum -= FirstLowInvalidHeapAttributeNumber;
    1586        2250 :         if (attnum <= 0 || attnum >= num_col_privileges)
    1587           0 :             elog(ERROR, "column number out of range");    /* safety check */
    1588        2250 :         col_privileges[attnum] |= this_privileges;
    1589             :     }
    1590         494 : }
    1591             : 
    1592             : /*
    1593             :  * expand_all_col_privileges
    1594             :  *
    1595             :  * OR the specified privilege(s) into per-column array entries for each valid
    1596             :  * attribute of a relation.  The per-column array is indexed starting at
    1597             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1598             :  */
    1599             : static void
    1600        3716 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
    1601             :                           AclMode this_privileges,
    1602             :                           AclMode *col_privileges,
    1603             :                           int num_col_privileges)
    1604             : {
    1605             :     AttrNumber  curr_att;
    1606             : 
    1607             :     Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
    1608       64132 :     for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
    1609       60416 :          curr_att <= classForm->relnatts;
    1610       56700 :          curr_att++)
    1611             :     {
    1612             :         HeapTuple   attTuple;
    1613             :         bool        isdropped;
    1614             : 
    1615       56700 :         if (curr_att == InvalidAttrNumber)
    1616        3716 :             continue;
    1617             : 
    1618             :         /* Views don't have any system columns at all */
    1619       52984 :         if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
    1620        9672 :             continue;
    1621             : 
    1622       43312 :         attTuple = SearchSysCache2(ATTNUM,
    1623             :                                    ObjectIdGetDatum(table_oid),
    1624             :                                    Int16GetDatum(curr_att));
    1625       43312 :         if (!HeapTupleIsValid(attTuple))
    1626           0 :             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1627             :                  curr_att, table_oid);
    1628             : 
    1629       43312 :         isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
    1630             : 
    1631       43312 :         ReleaseSysCache(attTuple);
    1632             : 
    1633             :         /* ignore dropped columns */
    1634       43312 :         if (isdropped)
    1635           4 :             continue;
    1636             : 
    1637       43308 :         col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
    1638             :     }
    1639        3716 : }
    1640             : 
    1641             : /*
    1642             :  *  This processes attributes, but expects to be called from
    1643             :  *  ExecGrant_Relation, not directly from ExecuteGrantStmt.
    1644             :  */
    1645             : static void
    1646       45530 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
    1647             :                     AttrNumber attnum, Oid ownerId, AclMode col_privileges,
    1648             :                     Relation attRelation, const Acl *old_rel_acl)
    1649             : {
    1650             :     HeapTuple   attr_tuple;
    1651             :     Form_pg_attribute pg_attribute_tuple;
    1652             :     Acl        *old_acl;
    1653             :     Acl        *new_acl;
    1654             :     Acl        *merged_acl;
    1655             :     Datum       aclDatum;
    1656             :     bool        isNull;
    1657             :     Oid         grantorId;
    1658             :     AclMode     avail_goptions;
    1659             :     bool        need_update;
    1660             :     HeapTuple   newtuple;
    1661             :     Datum       values[Natts_pg_attribute];
    1662             :     bool        nulls[Natts_pg_attribute];
    1663             :     bool        replaces[Natts_pg_attribute];
    1664             :     int         noldmembers;
    1665             :     int         nnewmembers;
    1666             :     Oid        *oldmembers;
    1667             :     Oid        *newmembers;
    1668             : 
    1669       45530 :     attr_tuple = SearchSysCache2(ATTNUM,
    1670             :                                  ObjectIdGetDatum(relOid),
    1671             :                                  Int16GetDatum(attnum));
    1672       45530 :     if (!HeapTupleIsValid(attr_tuple))
    1673           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1674             :              attnum, relOid);
    1675       45530 :     pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
    1676             : 
    1677             :     /*
    1678             :      * Get working copy of existing ACL. If there's no ACL, substitute the
    1679             :      * proper default.
    1680             :      */
    1681       45530 :     aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
    1682             :                                &isNull);
    1683       45530 :     if (isNull)
    1684             :     {
    1685       45430 :         old_acl = acldefault(OBJECT_COLUMN, ownerId);
    1686             :         /* There are no old member roles according to the catalogs */
    1687       45430 :         noldmembers = 0;
    1688       45430 :         oldmembers = NULL;
    1689             :     }
    1690             :     else
    1691             :     {
    1692         100 :         old_acl = DatumGetAclPCopy(aclDatum);
    1693             :         /* Get the roles mentioned in the existing ACL */
    1694         100 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1695             :     }
    1696             : 
    1697             :     /*
    1698             :      * In select_best_grantor we should consider existing table-level ACL bits
    1699             :      * as well as the per-column ACL.  Build a new ACL that is their
    1700             :      * concatenation.  (This is a bit cheap and dirty compared to merging them
    1701             :      * properly with no duplications, but it's all we need here.)
    1702             :      */
    1703       45530 :     merged_acl = aclconcat(old_rel_acl, old_acl);
    1704             : 
    1705             :     /* Determine ID to do the grant as, and available grant options */
    1706       45530 :     select_best_grantor(GetUserId(), col_privileges,
    1707             :                         merged_acl, ownerId,
    1708             :                         &grantorId, &avail_goptions);
    1709             : 
    1710       45530 :     pfree(merged_acl);
    1711             : 
    1712             :     /*
    1713             :      * Restrict the privileges to what we can actually grant, and emit the
    1714             :      * standards-mandated warning and error messages.  Note: we don't track
    1715             :      * whether the user actually used the ALL PRIVILEGES(columns) syntax for
    1716             :      * each column; we just approximate it by whether all the possible
    1717             :      * privileges are specified now.  Since the all_privs flag only determines
    1718             :      * whether a warning is issued, this seems close enough.
    1719             :      */
    1720       45530 :     col_privileges =
    1721       45530 :         restrict_and_check_grant(istmt->is_grant, avail_goptions,
    1722             :                                  (col_privileges == ACL_ALL_RIGHTS_COLUMN),
    1723             :                                  col_privileges,
    1724             :                                  relOid, grantorId, OBJECT_COLUMN,
    1725             :                                  relname, attnum,
    1726       45530 :                                  NameStr(pg_attribute_tuple->attname));
    1727             : 
    1728             :     /*
    1729             :      * Generate new ACL.
    1730             :      */
    1731       91060 :     new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    1732       45530 :                                    istmt->grant_option,
    1733             :                                    istmt->behavior, istmt->grantees,
    1734             :                                    col_privileges, grantorId,
    1735             :                                    ownerId);
    1736             : 
    1737             :     /*
    1738             :      * We need the members of both old and new ACLs so we can correct the
    1739             :      * shared dependency information.
    1740             :      */
    1741       45530 :     nnewmembers = aclmembers(new_acl, &newmembers);
    1742             : 
    1743             :     /* finished building new ACL value, now insert it */
    1744       45530 :     MemSet(values, 0, sizeof(values));
    1745       45530 :     MemSet(nulls, false, sizeof(nulls));
    1746       45530 :     MemSet(replaces, false, sizeof(replaces));
    1747             : 
    1748             :     /*
    1749             :      * If the updated ACL is empty, we can set attacl to null, and maybe even
    1750             :      * avoid an update of the pg_attribute row.  This is worth testing because
    1751             :      * we'll come through here multiple times for any relation-level REVOKE,
    1752             :      * even if there were never any column GRANTs.  Note we are assuming that
    1753             :      * the "default" ACL state for columns is empty.
    1754             :      */
    1755       45530 :     if (ACL_NUM(new_acl) > 0)
    1756             :     {
    1757        2238 :         values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
    1758        2238 :         need_update = true;
    1759             :     }
    1760             :     else
    1761             :     {
    1762       43292 :         nulls[Anum_pg_attribute_attacl - 1] = true;
    1763       43292 :         need_update = !isNull;
    1764             :     }
    1765       45530 :     replaces[Anum_pg_attribute_attacl - 1] = true;
    1766             : 
    1767       45530 :     if (need_update)
    1768             :     {
    1769        2266 :         newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
    1770             :                                      values, nulls, replaces);
    1771             : 
    1772        2266 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
    1773             : 
    1774             :         /* Update initial privileges for extensions */
    1775        2266 :         recordExtensionInitPriv(relOid, RelationRelationId, attnum,
    1776        2266 :                                 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
    1777             : 
    1778             :         /* Update the shared dependency ACL info */
    1779        2266 :         updateAclDependencies(RelationRelationId, relOid, attnum,
    1780             :                               ownerId,
    1781             :                               noldmembers, oldmembers,
    1782             :                               nnewmembers, newmembers);
    1783             :     }
    1784             : 
    1785       45530 :     pfree(new_acl);
    1786             : 
    1787       45530 :     ReleaseSysCache(attr_tuple);
    1788       45530 : }
    1789             : 
    1790             : /*
    1791             :  *  This processes both sequences and non-sequences.
    1792             :  */
    1793             : static void
    1794       23714 : ExecGrant_Relation(InternalGrant *istmt)
    1795             : {
    1796             :     Relation    relation;
    1797             :     Relation    attRelation;
    1798             :     ListCell   *cell;
    1799             : 
    1800       23714 :     relation = table_open(RelationRelationId, RowExclusiveLock);
    1801       23714 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
    1802             : 
    1803       47464 :     foreach(cell, istmt->objects)
    1804             :     {
    1805       23754 :         Oid         relOid = lfirst_oid(cell);
    1806             :         Datum       aclDatum;
    1807             :         Form_pg_class pg_class_tuple;
    1808             :         bool        isNull;
    1809             :         AclMode     this_privileges;
    1810             :         AclMode    *col_privileges;
    1811             :         int         num_col_privileges;
    1812             :         bool        have_col_privileges;
    1813             :         Acl        *old_acl;
    1814             :         Acl        *old_rel_acl;
    1815             :         int         noldmembers;
    1816             :         Oid        *oldmembers;
    1817             :         Oid         ownerId;
    1818             :         HeapTuple   tuple;
    1819             :         ListCell   *cell_colprivs;
    1820             : 
    1821       23754 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
    1822       23754 :         if (!HeapTupleIsValid(tuple))
    1823           0 :             elog(ERROR, "cache lookup failed for relation %u", relOid);
    1824       23754 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    1825             : 
    1826             :         /* Not sensible to grant on an index */
    1827       47508 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    1828       23754 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    1829           0 :             ereport(ERROR,
    1830             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1831             :                      errmsg("\"%s\" is an index",
    1832             :                             NameStr(pg_class_tuple->relname))));
    1833             : 
    1834             :         /* Composite types aren't tables either */
    1835       23754 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    1836           0 :             ereport(ERROR,
    1837             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1838             :                      errmsg("\"%s\" is a composite type",
    1839             :                             NameStr(pg_class_tuple->relname))));
    1840             : 
    1841             :         /* Used GRANT SEQUENCE on a non-sequence? */
    1842       23756 :         if (istmt->objtype == OBJECT_SEQUENCE &&
    1843           2 :             pg_class_tuple->relkind != RELKIND_SEQUENCE)
    1844           0 :             ereport(ERROR,
    1845             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1846             :                      errmsg("\"%s\" is not a sequence",
    1847             :                             NameStr(pg_class_tuple->relname))));
    1848             : 
    1849             :         /* Adjust the default permissions based on object type */
    1850       23754 :         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    1851             :         {
    1852        7556 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1853          40 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1854             :             else
    1855        3738 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1856             :         }
    1857             :         else
    1858       19976 :             this_privileges = istmt->privileges;
    1859             : 
    1860             :         /*
    1861             :          * The GRANT TABLE syntax can be used for sequences and non-sequences,
    1862             :          * so we have to look at the relkind to determine the supported
    1863             :          * permissions.  The OR of table and sequence permissions were already
    1864             :          * checked.
    1865             :          */
    1866       23754 :         if (istmt->objtype == OBJECT_TABLE)
    1867             :         {
    1868       23752 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1869             :             {
    1870             :                 /*
    1871             :                  * For backward compatibility, just throw a warning for
    1872             :                  * invalid sequence permissions when using the non-sequence
    1873             :                  * GRANT syntax.
    1874             :                  */
    1875          92 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
    1876             :                 {
    1877             :                     /*
    1878             :                      * Mention the object name because the user needs to know
    1879             :                      * which operations succeeded.  This is required because
    1880             :                      * WARNING allows the command to continue.
    1881             :                      */
    1882           0 :                     ereport(WARNING,
    1883             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1884             :                              errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
    1885             :                                     NameStr(pg_class_tuple->relname))));
    1886           0 :                     this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
    1887             :                 }
    1888             :             }
    1889             :             else
    1890             :             {
    1891       23660 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
    1892             :                 {
    1893             :                     /*
    1894             :                      * USAGE is the only permission supported by sequences but
    1895             :                      * not by non-sequences.  Don't mention the object name
    1896             :                      * because we didn't in the combined TABLE | SEQUENCE
    1897             :                      * check.
    1898             :                      */
    1899           0 :                     ereport(ERROR,
    1900             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1901             :                              errmsg("invalid privilege type %s for table",
    1902             :                                     "USAGE")));
    1903             :                 }
    1904             :             }
    1905             :         }
    1906             : 
    1907             :         /*
    1908             :          * Set up array in which we'll accumulate any column privilege bits
    1909             :          * that need modification.  The array is indexed such that entry [0]
    1910             :          * corresponds to FirstLowInvalidHeapAttributeNumber.
    1911             :          */
    1912       23754 :         num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
    1913       23754 :         col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
    1914       23754 :         have_col_privileges = false;
    1915             : 
    1916             :         /*
    1917             :          * If we are revoking relation privileges that are also column
    1918             :          * privileges, we must implicitly revoke them from each column too,
    1919             :          * per SQL spec.  (We don't need to implicitly add column privileges
    1920             :          * during GRANT because the permissions-checking code always checks
    1921             :          * both relation and per-column privileges.)
    1922             :          */
    1923       27502 :         if (!istmt->is_grant &&
    1924        3748 :             (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
    1925             :         {
    1926        3716 :             expand_all_col_privileges(relOid, pg_class_tuple,
    1927             :                                       this_privileges & ACL_ALL_RIGHTS_COLUMN,
    1928             :                                       col_privileges,
    1929             :                                       num_col_privileges);
    1930        3716 :             have_col_privileges = true;
    1931             :         }
    1932             : 
    1933             :         /*
    1934             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    1935             :          * substitute the proper default.
    1936             :          */
    1937       23754 :         ownerId = pg_class_tuple->relowner;
    1938       23754 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    1939             :                                    &isNull);
    1940       23754 :         if (isNull)
    1941             :         {
    1942       22762 :             switch (pg_class_tuple->relkind)
    1943             :             {
    1944             :                 case RELKIND_SEQUENCE:
    1945          54 :                     old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
    1946          54 :                     break;
    1947             :                 default:
    1948       22708 :                     old_acl = acldefault(OBJECT_TABLE, ownerId);
    1949       22708 :                     break;
    1950             :             }
    1951             :             /* There are no old member roles according to the catalogs */
    1952       22762 :             noldmembers = 0;
    1953       22762 :             oldmembers = NULL;
    1954             :         }
    1955             :         else
    1956             :         {
    1957         992 :             old_acl = DatumGetAclPCopy(aclDatum);
    1958             :             /* Get the roles mentioned in the existing ACL */
    1959         992 :             noldmembers = aclmembers(old_acl, &oldmembers);
    1960             :         }
    1961             : 
    1962             :         /* Need an extra copy of original rel ACL for column handling */
    1963       23754 :         old_rel_acl = aclcopy(old_acl);
    1964             : 
    1965             :         /*
    1966             :          * Handle relation-level privileges, if any were specified
    1967             :          */
    1968       23754 :         if (this_privileges != ACL_NO_RIGHTS)
    1969             :         {
    1970             :             AclMode     avail_goptions;
    1971             :             Acl        *new_acl;
    1972             :             Oid         grantorId;
    1973             :             HeapTuple   newtuple;
    1974             :             Datum       values[Natts_pg_class];
    1975             :             bool        nulls[Natts_pg_class];
    1976             :             bool        replaces[Natts_pg_class];
    1977             :             int         nnewmembers;
    1978             :             Oid        *newmembers;
    1979             :             ObjectType  objtype;
    1980             : 
    1981             :             /* Determine ID to do the grant as, and available grant options */
    1982       23268 :             select_best_grantor(GetUserId(), this_privileges,
    1983             :                                 old_acl, ownerId,
    1984             :                                 &grantorId, &avail_goptions);
    1985             : 
    1986       23268 :             switch (pg_class_tuple->relkind)
    1987             :             {
    1988             :                 case RELKIND_SEQUENCE:
    1989          94 :                     objtype = OBJECT_SEQUENCE;
    1990          94 :                     break;
    1991             :                 default:
    1992       23174 :                     objtype = OBJECT_TABLE;
    1993       23174 :                     break;
    1994             :             }
    1995             : 
    1996             :             /*
    1997             :              * Restrict the privileges to what we can actually grant, and emit
    1998             :              * the standards-mandated warning and error messages.
    1999             :              */
    2000       23268 :             this_privileges =
    2001       46536 :                 restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2002       23268 :                                          istmt->all_privs, this_privileges,
    2003             :                                          relOid, grantorId, objtype,
    2004       23268 :                                          NameStr(pg_class_tuple->relname),
    2005             :                                          0, NULL);
    2006             : 
    2007             :             /*
    2008             :              * Generate new ACL.
    2009             :              */
    2010       69804 :             new_acl = merge_acl_with_grant(old_acl,
    2011       23268 :                                            istmt->is_grant,
    2012       23268 :                                            istmt->grant_option,
    2013             :                                            istmt->behavior,
    2014             :                                            istmt->grantees,
    2015             :                                            this_privileges,
    2016             :                                            grantorId,
    2017             :                                            ownerId);
    2018             : 
    2019             :             /*
    2020             :              * We need the members of both old and new ACLs so we can correct
    2021             :              * the shared dependency information.
    2022             :              */
    2023       23264 :             nnewmembers = aclmembers(new_acl, &newmembers);
    2024             : 
    2025             :             /* finished building new ACL value, now insert it */
    2026       23264 :             MemSet(values, 0, sizeof(values));
    2027       23264 :             MemSet(nulls, false, sizeof(nulls));
    2028       23264 :             MemSet(replaces, false, sizeof(replaces));
    2029             : 
    2030       23264 :             replaces[Anum_pg_class_relacl - 1] = true;
    2031       23264 :             values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
    2032             : 
    2033       23264 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2034             :                                          values, nulls, replaces);
    2035             : 
    2036       23264 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2037             : 
    2038             :             /* Update initial privileges for extensions */
    2039       23264 :             recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
    2040             : 
    2041             :             /* Update the shared dependency ACL info */
    2042       23264 :             updateAclDependencies(RelationRelationId, relOid, 0,
    2043             :                                   ownerId,
    2044             :                                   noldmembers, oldmembers,
    2045             :                                   nnewmembers, newmembers);
    2046             : 
    2047       23264 :             pfree(new_acl);
    2048             :         }
    2049             : 
    2050             :         /*
    2051             :          * Handle column-level privileges, if any were specified or implied.
    2052             :          * We first expand the user-specified column privileges into the
    2053             :          * array, and then iterate over all nonempty array entries.
    2054             :          */
    2055       24244 :         foreach(cell_colprivs, istmt->col_privs)
    2056             :         {
    2057         494 :             AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
    2058             : 
    2059         494 :             if (col_privs->priv_name == NULL)
    2060          12 :                 this_privileges = ACL_ALL_RIGHTS_COLUMN;
    2061             :             else
    2062         482 :                 this_privileges = string_to_privilege(col_privs->priv_name);
    2063             : 
    2064         494 :             if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
    2065           0 :                 ereport(ERROR,
    2066             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2067             :                          errmsg("invalid privilege type %s for column",
    2068             :                                 privilege_to_string(this_privileges))));
    2069             : 
    2070         494 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
    2071           0 :                 this_privileges & ~((AclMode) ACL_SELECT))
    2072             :             {
    2073             :                 /*
    2074             :                  * The only column privilege allowed on sequences is SELECT.
    2075             :                  * This is a warning not error because we do it that way for
    2076             :                  * relation-level privileges.
    2077             :                  */
    2078           0 :                 ereport(WARNING,
    2079             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2080             :                          errmsg("sequence \"%s\" only supports SELECT column privileges",
    2081             :                                 NameStr(pg_class_tuple->relname))));
    2082             : 
    2083           0 :                 this_privileges &= (AclMode) ACL_SELECT;
    2084             :             }
    2085             : 
    2086         494 :             expand_col_privileges(col_privs->cols, relOid,
    2087             :                                   this_privileges,
    2088             :                                   col_privileges,
    2089             :                                   num_col_privileges);
    2090         494 :             have_col_privileges = true;
    2091             :         }
    2092             : 
    2093       23750 :         if (have_col_privileges)
    2094             :         {
    2095             :             AttrNumber  i;
    2096             : 
    2097       72150 :             for (i = 0; i < num_col_privileges; i++)
    2098             :             {
    2099       67952 :                 if (col_privileges[i] == ACL_NO_RIGHTS)
    2100       22422 :                     continue;
    2101      136590 :                 ExecGrant_Attribute(istmt,
    2102             :                                     relOid,
    2103       45530 :                                     NameStr(pg_class_tuple->relname),
    2104       45530 :                                     i + FirstLowInvalidHeapAttributeNumber,
    2105             :                                     ownerId,
    2106       45530 :                                     col_privileges[i],
    2107             :                                     attRelation,
    2108             :                                     old_rel_acl);
    2109             :             }
    2110             :         }
    2111             : 
    2112       23750 :         pfree(old_rel_acl);
    2113       23750 :         pfree(col_privileges);
    2114             : 
    2115       23750 :         ReleaseSysCache(tuple);
    2116             : 
    2117             :         /* prevent error when processing duplicate objects */
    2118       23750 :         CommandCounterIncrement();
    2119             :     }
    2120             : 
    2121       23710 :     table_close(attRelation, RowExclusiveLock);
    2122       23710 :     table_close(relation, RowExclusiveLock);
    2123       23710 : }
    2124             : 
    2125             : static void
    2126         684 : ExecGrant_Database(InternalGrant *istmt)
    2127             : {
    2128             :     Relation    relation;
    2129             :     ListCell   *cell;
    2130             : 
    2131         684 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2132          20 :         istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
    2133             : 
    2134         684 :     relation = table_open(DatabaseRelationId, RowExclusiveLock);
    2135             : 
    2136        1368 :     foreach(cell, istmt->objects)
    2137             :     {
    2138         684 :         Oid         datId = lfirst_oid(cell);
    2139             :         Form_pg_database pg_database_tuple;
    2140             :         Datum       aclDatum;
    2141             :         bool        isNull;
    2142             :         AclMode     avail_goptions;
    2143             :         AclMode     this_privileges;
    2144             :         Acl        *old_acl;
    2145             :         Acl        *new_acl;
    2146             :         Oid         grantorId;
    2147             :         Oid         ownerId;
    2148             :         HeapTuple   newtuple;
    2149             :         Datum       values[Natts_pg_database];
    2150             :         bool        nulls[Natts_pg_database];
    2151             :         bool        replaces[Natts_pg_database];
    2152             :         int         noldmembers;
    2153             :         int         nnewmembers;
    2154             :         Oid        *oldmembers;
    2155             :         Oid        *newmembers;
    2156             :         HeapTuple   tuple;
    2157             : 
    2158         684 :         tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
    2159         684 :         if (!HeapTupleIsValid(tuple))
    2160           0 :             elog(ERROR, "cache lookup failed for database %u", datId);
    2161             : 
    2162         684 :         pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
    2163             : 
    2164             :         /*
    2165             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2166             :          * substitute the proper default.
    2167             :          */
    2168         684 :         ownerId = pg_database_tuple->datdba;
    2169         684 :         aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
    2170             :                                 RelationGetDescr(relation), &isNull);
    2171         684 :         if (isNull)
    2172             :         {
    2173         660 :             old_acl = acldefault(OBJECT_DATABASE, ownerId);
    2174             :             /* There are no old member roles according to the catalogs */
    2175         660 :             noldmembers = 0;
    2176         660 :             oldmembers = NULL;
    2177             :         }
    2178             :         else
    2179             :         {
    2180          24 :             old_acl = DatumGetAclPCopy(aclDatum);
    2181             :             /* Get the roles mentioned in the existing ACL */
    2182          24 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2183             :         }
    2184             : 
    2185             :         /* Determine ID to do the grant as, and available grant options */
    2186         684 :         select_best_grantor(GetUserId(), istmt->privileges,
    2187             :                             old_acl, ownerId,
    2188             :                             &grantorId, &avail_goptions);
    2189             : 
    2190             :         /*
    2191             :          * Restrict the privileges to what we can actually grant, and emit the
    2192             :          * standards-mandated warning and error messages.
    2193             :          */
    2194         684 :         this_privileges =
    2195        1368 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2196         684 :                                      istmt->all_privs, istmt->privileges,
    2197             :                                      datId, grantorId, OBJECT_DATABASE,
    2198         684 :                                      NameStr(pg_database_tuple->datname),
    2199             :                                      0, NULL);
    2200             : 
    2201             :         /*
    2202             :          * Generate new ACL.
    2203             :          */
    2204        1368 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2205         684 :                                        istmt->grant_option, istmt->behavior,
    2206             :                                        istmt->grantees, this_privileges,
    2207             :                                        grantorId, ownerId);
    2208             : 
    2209             :         /*
    2210             :          * We need the members of both old and new ACLs so we can correct the
    2211             :          * shared dependency information.
    2212             :          */
    2213         684 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2214             : 
    2215             :         /* finished building new ACL value, now insert it */
    2216         684 :         MemSet(values, 0, sizeof(values));
    2217         684 :         MemSet(nulls, false, sizeof(nulls));
    2218         684 :         MemSet(replaces, false, sizeof(replaces));
    2219             : 
    2220         684 :         replaces[Anum_pg_database_datacl - 1] = true;
    2221         684 :         values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
    2222             : 
    2223         684 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2224             :                                      nulls, replaces);
    2225             : 
    2226         684 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2227             : 
    2228             :         /* Update the shared dependency ACL info */
    2229         684 :         updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0,
    2230             :                               ownerId,
    2231             :                               noldmembers, oldmembers,
    2232             :                               nnewmembers, newmembers);
    2233             : 
    2234         684 :         ReleaseSysCache(tuple);
    2235             : 
    2236         684 :         pfree(new_acl);
    2237             : 
    2238             :         /* prevent error when processing duplicate objects */
    2239         684 :         CommandCounterIncrement();
    2240             :     }
    2241             : 
    2242         684 :     table_close(relation, RowExclusiveLock);
    2243         684 : }
    2244             : 
    2245             : static void
    2246          62 : ExecGrant_Fdw(InternalGrant *istmt)
    2247             : {
    2248             :     Relation    relation;
    2249             :     ListCell   *cell;
    2250             : 
    2251          62 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2252           4 :         istmt->privileges = ACL_ALL_RIGHTS_FDW;
    2253             : 
    2254          62 :     relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
    2255             : 
    2256         112 :     foreach(cell, istmt->objects)
    2257             :     {
    2258          62 :         Oid         fdwid = lfirst_oid(cell);
    2259             :         Form_pg_foreign_data_wrapper pg_fdw_tuple;
    2260             :         Datum       aclDatum;
    2261             :         bool        isNull;
    2262             :         AclMode     avail_goptions;
    2263             :         AclMode     this_privileges;
    2264             :         Acl        *old_acl;
    2265             :         Acl        *new_acl;
    2266             :         Oid         grantorId;
    2267             :         Oid         ownerId;
    2268             :         HeapTuple   tuple;
    2269             :         HeapTuple   newtuple;
    2270             :         Datum       values[Natts_pg_foreign_data_wrapper];
    2271             :         bool        nulls[Natts_pg_foreign_data_wrapper];
    2272             :         bool        replaces[Natts_pg_foreign_data_wrapper];
    2273             :         int         noldmembers;
    2274             :         int         nnewmembers;
    2275             :         Oid        *oldmembers;
    2276             :         Oid        *newmembers;
    2277             : 
    2278          62 :         tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
    2279             :                                 ObjectIdGetDatum(fdwid));
    2280          62 :         if (!HeapTupleIsValid(tuple))
    2281           0 :             elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
    2282             : 
    2283          62 :         pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
    2284             : 
    2285             :         /*
    2286             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2287             :          * substitute the proper default.
    2288             :          */
    2289          62 :         ownerId = pg_fdw_tuple->fdwowner;
    2290          62 :         aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
    2291             :                                    Anum_pg_foreign_data_wrapper_fdwacl,
    2292             :                                    &isNull);
    2293          62 :         if (isNull)
    2294             :         {
    2295          12 :             old_acl = acldefault(OBJECT_FDW, ownerId);
    2296             :             /* There are no old member roles according to the catalogs */
    2297          12 :             noldmembers = 0;
    2298          12 :             oldmembers = NULL;
    2299             :         }
    2300             :         else
    2301             :         {
    2302          50 :             old_acl = DatumGetAclPCopy(aclDatum);
    2303             :             /* Get the roles mentioned in the existing ACL */
    2304          50 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2305             :         }
    2306             : 
    2307             :         /* Determine ID to do the grant as, and available grant options */
    2308          62 :         select_best_grantor(GetUserId(), istmt->privileges,
    2309             :                             old_acl, ownerId,
    2310             :                             &grantorId, &avail_goptions);
    2311             : 
    2312             :         /*
    2313             :          * Restrict the privileges to what we can actually grant, and emit the
    2314             :          * standards-mandated warning and error messages.
    2315             :          */
    2316          62 :         this_privileges =
    2317         124 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2318          62 :                                      istmt->all_privs, istmt->privileges,
    2319             :                                      fdwid, grantorId, OBJECT_FDW,
    2320          62 :                                      NameStr(pg_fdw_tuple->fdwname),
    2321             :                                      0, NULL);
    2322             : 
    2323             :         /*
    2324             :          * Generate new ACL.
    2325             :          */
    2326         108 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2327          54 :                                        istmt->grant_option, istmt->behavior,
    2328             :                                        istmt->grantees, this_privileges,
    2329             :                                        grantorId, ownerId);
    2330             : 
    2331             :         /*
    2332             :          * We need the members of both old and new ACLs so we can correct the
    2333             :          * shared dependency information.
    2334             :          */
    2335          50 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2336             : 
    2337             :         /* finished building new ACL value, now insert it */
    2338          50 :         MemSet(values, 0, sizeof(values));
    2339          50 :         MemSet(nulls, false, sizeof(nulls));
    2340          50 :         MemSet(replaces, false, sizeof(replaces));
    2341             : 
    2342          50 :         replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
    2343          50 :         values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
    2344             : 
    2345          50 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2346             :                                      nulls, replaces);
    2347             : 
    2348          50 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2349             : 
    2350             :         /* Update initial privileges for extensions */
    2351          50 :         recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
    2352             :                                 new_acl);
    2353             : 
    2354             :         /* Update the shared dependency ACL info */
    2355          50 :         updateAclDependencies(ForeignDataWrapperRelationId,
    2356             :                               pg_fdw_tuple->oid, 0,
    2357             :                               ownerId,
    2358             :                               noldmembers, oldmembers,
    2359             :                               nnewmembers, newmembers);
    2360             : 
    2361          50 :         ReleaseSysCache(tuple);
    2362             : 
    2363          50 :         pfree(new_acl);
    2364             : 
    2365             :         /* prevent error when processing duplicate objects */
    2366          50 :         CommandCounterIncrement();
    2367             :     }
    2368             : 
    2369          50 :     table_close(relation, RowExclusiveLock);
    2370          50 : }
    2371             : 
    2372             : static void
    2373          62 : ExecGrant_ForeignServer(InternalGrant *istmt)
    2374             : {
    2375             :     Relation    relation;
    2376             :     ListCell   *cell;
    2377             : 
    2378          62 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2379           8 :         istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
    2380             : 
    2381          62 :     relation = table_open(ForeignServerRelationId, RowExclusiveLock);
    2382             : 
    2383         116 :     foreach(cell, istmt->objects)
    2384             :     {
    2385          62 :         Oid         srvid = lfirst_oid(cell);
    2386             :         Form_pg_foreign_server pg_server_tuple;
    2387             :         Datum       aclDatum;
    2388             :         bool        isNull;
    2389             :         AclMode     avail_goptions;
    2390             :         AclMode     this_privileges;
    2391             :         Acl        *old_acl;
    2392             :         Acl        *new_acl;
    2393             :         Oid         grantorId;
    2394             :         Oid         ownerId;
    2395             :         HeapTuple   tuple;
    2396             :         HeapTuple   newtuple;
    2397             :         Datum       values[Natts_pg_foreign_server];
    2398             :         bool        nulls[Natts_pg_foreign_server];
    2399             :         bool        replaces[Natts_pg_foreign_server];
    2400             :         int         noldmembers;
    2401             :         int         nnewmembers;
    2402             :         Oid        *oldmembers;
    2403             :         Oid        *newmembers;
    2404             : 
    2405          62 :         tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
    2406          62 :         if (!HeapTupleIsValid(tuple))
    2407           0 :             elog(ERROR, "cache lookup failed for foreign server %u", srvid);
    2408             : 
    2409          62 :         pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
    2410             : 
    2411             :         /*
    2412             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2413             :          * substitute the proper default.
    2414             :          */
    2415          62 :         ownerId = pg_server_tuple->srvowner;
    2416          62 :         aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
    2417             :                                    Anum_pg_foreign_server_srvacl,
    2418             :                                    &isNull);
    2419          62 :         if (isNull)
    2420             :         {
    2421          32 :             old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
    2422             :             /* There are no old member roles according to the catalogs */
    2423          32 :             noldmembers = 0;
    2424          32 :             oldmembers = NULL;
    2425             :         }
    2426             :         else
    2427             :         {
    2428          30 :             old_acl = DatumGetAclPCopy(aclDatum);
    2429             :             /* Get the roles mentioned in the existing ACL */
    2430          30 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2431             :         }
    2432             : 
    2433             :         /* Determine ID to do the grant as, and available grant options */
    2434          62 :         select_best_grantor(GetUserId(), istmt->privileges,
    2435             :                             old_acl, ownerId,
    2436             :                             &grantorId, &avail_goptions);
    2437             : 
    2438             :         /*
    2439             :          * Restrict the privileges to what we can actually grant, and emit the
    2440             :          * standards-mandated warning and error messages.
    2441             :          */
    2442          62 :         this_privileges =
    2443         124 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2444          62 :                                      istmt->all_privs, istmt->privileges,
    2445             :                                      srvid, grantorId, OBJECT_FOREIGN_SERVER,
    2446          62 :                                      NameStr(pg_server_tuple->srvname),
    2447             :                                      0, NULL);
    2448             : 
    2449             :         /*
    2450             :          * Generate new ACL.
    2451             :          */
    2452         108 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2453          54 :                                        istmt->grant_option, istmt->behavior,
    2454             :                                        istmt->grantees, this_privileges,
    2455             :                                        grantorId, ownerId);
    2456             : 
    2457             :         /*
    2458             :          * We need the members of both old and new ACLs so we can correct the
    2459             :          * shared dependency information.
    2460             :          */
    2461          54 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2462             : 
    2463             :         /* finished building new ACL value, now insert it */
    2464          54 :         MemSet(values, 0, sizeof(values));
    2465          54 :         MemSet(nulls, false, sizeof(nulls));
    2466          54 :         MemSet(replaces, false, sizeof(replaces));
    2467             : 
    2468          54 :         replaces[Anum_pg_foreign_server_srvacl - 1] = true;
    2469          54 :         values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
    2470             : 
    2471          54 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2472             :                                      nulls, replaces);
    2473             : 
    2474          54 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2475             : 
    2476             :         /* Update initial privileges for extensions */
    2477          54 :         recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
    2478             : 
    2479             :         /* Update the shared dependency ACL info */
    2480          54 :         updateAclDependencies(ForeignServerRelationId,
    2481             :                               pg_server_tuple->oid, 0,
    2482             :                               ownerId,
    2483             :                               noldmembers, oldmembers,
    2484             :                               nnewmembers, newmembers);
    2485             : 
    2486          54 :         ReleaseSysCache(tuple);
    2487             : 
    2488          54 :         pfree(new_acl);
    2489             : 
    2490             :         /* prevent error when processing duplicate objects */
    2491          54 :         CommandCounterIncrement();
    2492             :     }
    2493             : 
    2494          54 :     table_close(relation, RowExclusiveLock);
    2495          54 : }
    2496             : 
    2497             : static void
    2498       13862 : ExecGrant_Function(InternalGrant *istmt)
    2499             : {
    2500             :     Relation    relation;
    2501             :     ListCell   *cell;
    2502             : 
    2503       13862 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2504         134 :         istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
    2505             : 
    2506       13862 :     relation = table_open(ProcedureRelationId, RowExclusiveLock);
    2507             : 
    2508       27752 :     foreach(cell, istmt->objects)
    2509             :     {
    2510       13890 :         Oid         funcId = lfirst_oid(cell);
    2511             :         Form_pg_proc pg_proc_tuple;
    2512             :         Datum       aclDatum;
    2513             :         bool        isNull;
    2514             :         AclMode     avail_goptions;
    2515             :         AclMode     this_privileges;
    2516             :         Acl        *old_acl;
    2517             :         Acl        *new_acl;
    2518             :         Oid         grantorId;
    2519             :         Oid         ownerId;
    2520             :         HeapTuple   tuple;
    2521             :         HeapTuple   newtuple;
    2522             :         Datum       values[Natts_pg_proc];
    2523             :         bool        nulls[Natts_pg_proc];
    2524             :         bool        replaces[Natts_pg_proc];
    2525             :         int         noldmembers;
    2526             :         int         nnewmembers;
    2527             :         Oid        *oldmembers;
    2528             :         Oid        *newmembers;
    2529             : 
    2530       13890 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
    2531       13890 :         if (!HeapTupleIsValid(tuple))
    2532           0 :             elog(ERROR, "cache lookup failed for function %u", funcId);
    2533             : 
    2534       13890 :         pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
    2535             : 
    2536             :         /*
    2537             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2538             :          * substitute the proper default.
    2539             :          */
    2540       13890 :         ownerId = pg_proc_tuple->proowner;
    2541       13890 :         aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
    2542             :                                    &isNull);
    2543       13890 :         if (isNull)
    2544             :         {
    2545       12060 :             old_acl = acldefault(OBJECT_FUNCTION, ownerId);
    2546             :             /* There are no old member roles according to the catalogs */
    2547       12060 :             noldmembers = 0;
    2548       12060 :             oldmembers = NULL;
    2549             :         }
    2550             :         else
    2551             :         {
    2552        1830 :             old_acl = DatumGetAclPCopy(aclDatum);
    2553             :             /* Get the roles mentioned in the existing ACL */
    2554        1830 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2555             :         }
    2556             : 
    2557             :         /* Determine ID to do the grant as, and available grant options */
    2558       13890 :         select_best_grantor(GetUserId(), istmt->privileges,
    2559             :                             old_acl, ownerId,
    2560             :                             &grantorId, &avail_goptions);
    2561             : 
    2562             :         /*
    2563             :          * Restrict the privileges to what we can actually grant, and emit the
    2564             :          * standards-mandated warning and error messages.
    2565             :          */
    2566       13890 :         this_privileges =
    2567       27780 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2568       13890 :                                      istmt->all_privs, istmt->privileges,
    2569             :                                      funcId, grantorId, OBJECT_FUNCTION,
    2570       13890 :                                      NameStr(pg_proc_tuple->proname),
    2571             :                                      0, NULL);
    2572             : 
    2573             :         /*
    2574             :          * Generate new ACL.
    2575             :          */
    2576       27780 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2577       13890 :                                        istmt->grant_option, istmt->behavior,
    2578             :                                        istmt->grantees, this_privileges,
    2579             :                                        grantorId, ownerId);
    2580             : 
    2581             :         /*
    2582             :          * We need the members of both old and new ACLs so we can correct the
    2583             :          * shared dependency information.
    2584             :          */
    2585       13890 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2586             : 
    2587             :         /* finished building new ACL value, now insert it */
    2588       13890 :         MemSet(values, 0, sizeof(values));
    2589       13890 :         MemSet(nulls, false, sizeof(nulls));
    2590       13890 :         MemSet(replaces, false, sizeof(replaces));
    2591             : 
    2592       13890 :         replaces[Anum_pg_proc_proacl - 1] = true;
    2593       13890 :         values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
    2594             : 
    2595       13890 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2596             :                                      nulls, replaces);
    2597             : 
    2598       13890 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2599             : 
    2600             :         /* Update initial privileges for extensions */
    2601       13890 :         recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
    2602             : 
    2603             :         /* Update the shared dependency ACL info */
    2604       13890 :         updateAclDependencies(ProcedureRelationId, funcId, 0,
    2605             :                               ownerId,
    2606             :                               noldmembers, oldmembers,
    2607             :                               nnewmembers, newmembers);
    2608             : 
    2609       13890 :         ReleaseSysCache(tuple);
    2610             : 
    2611       13890 :         pfree(new_acl);
    2612             : 
    2613             :         /* prevent error when processing duplicate objects */
    2614       13890 :         CommandCounterIncrement();
    2615             :     }
    2616             : 
    2617       13862 :     table_close(relation, RowExclusiveLock);
    2618       13862 : }
    2619             : 
    2620             : static void
    2621          26 : ExecGrant_Language(InternalGrant *istmt)
    2622             : {
    2623             :     Relation    relation;
    2624             :     ListCell   *cell;
    2625             : 
    2626          26 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2627           8 :         istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
    2628             : 
    2629          26 :     relation = table_open(LanguageRelationId, RowExclusiveLock);
    2630             : 
    2631          48 :     foreach(cell, istmt->objects)
    2632             :     {
    2633          26 :         Oid         langId = lfirst_oid(cell);
    2634             :         Form_pg_language pg_language_tuple;
    2635             :         Datum       aclDatum;
    2636             :         bool        isNull;
    2637             :         AclMode     avail_goptions;
    2638             :         AclMode     this_privileges;
    2639             :         Acl        *old_acl;
    2640             :         Acl        *new_acl;
    2641             :         Oid         grantorId;
    2642             :         Oid         ownerId;
    2643             :         HeapTuple   tuple;
    2644             :         HeapTuple   newtuple;
    2645             :         Datum       values[Natts_pg_language];
    2646             :         bool        nulls[Natts_pg_language];
    2647             :         bool        replaces[Natts_pg_language];
    2648             :         int         noldmembers;
    2649             :         int         nnewmembers;
    2650             :         Oid        *oldmembers;
    2651             :         Oid        *newmembers;
    2652             : 
    2653          26 :         tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
    2654          26 :         if (!HeapTupleIsValid(tuple))
    2655           0 :             elog(ERROR, "cache lookup failed for language %u", langId);
    2656             : 
    2657          26 :         pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
    2658             : 
    2659          26 :         if (!pg_language_tuple->lanpltrusted)
    2660           4 :             ereport(ERROR,
    2661             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2662             :                      errmsg("language \"%s\" is not trusted",
    2663             :                             NameStr(pg_language_tuple->lanname)),
    2664             :                      errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
    2665             :                                "because only superusers can use untrusted languages.")));
    2666             : 
    2667             :         /*
    2668             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2669             :          * substitute the proper default.
    2670             :          */
    2671          22 :         ownerId = pg_language_tuple->lanowner;
    2672          22 :         aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
    2673             :                                    &isNull);
    2674          22 :         if (isNull)
    2675             :         {
    2676           6 :             old_acl = acldefault(OBJECT_LANGUAGE, ownerId);
    2677             :             /* There are no old member roles according to the catalogs */
    2678           6 :             noldmembers = 0;
    2679           6 :             oldmembers = NULL;
    2680             :         }
    2681             :         else
    2682             :         {
    2683          16 :             old_acl = DatumGetAclPCopy(aclDatum);
    2684             :             /* Get the roles mentioned in the existing ACL */
    2685          16 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2686             :         }
    2687             : 
    2688             :         /* Determine ID to do the grant as, and available grant options */
    2689          22 :         select_best_grantor(GetUserId(), istmt->privileges,
    2690             :                             old_acl, ownerId,
    2691             :                             &grantorId, &avail_goptions);
    2692             : 
    2693             :         /*
    2694             :          * Restrict the privileges to what we can actually grant, and emit the
    2695             :          * standards-mandated warning and error messages.
    2696             :          */
    2697          22 :         this_privileges =
    2698          44 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2699          22 :                                      istmt->all_privs, istmt->privileges,
    2700             :                                      langId, grantorId, OBJECT_LANGUAGE,
    2701          22 :                                      NameStr(pg_language_tuple->lanname),
    2702             :                                      0, NULL);
    2703             : 
    2704             :         /*
    2705             :          * Generate new ACL.
    2706             :          */
    2707          44 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2708          22 :                                        istmt->grant_option, istmt->behavior,
    2709             :                                        istmt->grantees, this_privileges,
    2710             :                                        grantorId, ownerId);
    2711             : 
    2712             :         /*
    2713             :          * We need the members of both old and new ACLs so we can correct the
    2714             :          * shared dependency information.
    2715             :          */
    2716          22 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2717             : 
    2718             :         /* finished building new ACL value, now insert it */
    2719          22 :         MemSet(values, 0, sizeof(values));
    2720          22 :         MemSet(nulls, false, sizeof(nulls));
    2721          22 :         MemSet(replaces, false, sizeof(replaces));
    2722             : 
    2723          22 :         replaces[Anum_pg_language_lanacl - 1] = true;
    2724          22 :         values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
    2725             : 
    2726          22 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2727             :                                      nulls, replaces);
    2728             : 
    2729          22 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2730             : 
    2731             :         /* Update initial privileges for extensions */
    2732          22 :         recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
    2733             : 
    2734             :         /* Update the shared dependency ACL info */
    2735          22 :         updateAclDependencies(LanguageRelationId, pg_language_tuple->oid, 0,
    2736             :                               ownerId,
    2737             :                               noldmembers, oldmembers,
    2738             :                               nnewmembers, newmembers);
    2739             : 
    2740          22 :         ReleaseSysCache(tuple);
    2741             : 
    2742          22 :         pfree(new_acl);
    2743             : 
    2744             :         /* prevent error when processing duplicate objects */
    2745          22 :         CommandCounterIncrement();
    2746             :     }
    2747             : 
    2748          22 :     table_close(relation, RowExclusiveLock);
    2749          22 : }
    2750             : 
    2751             : static void
    2752          34 : ExecGrant_Largeobject(InternalGrant *istmt)
    2753             : {
    2754             :     Relation    relation;
    2755             :     ListCell   *cell;
    2756             : 
    2757          34 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2758          18 :         istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    2759             : 
    2760          34 :     relation = table_open(LargeObjectMetadataRelationId,
    2761             :                           RowExclusiveLock);
    2762             : 
    2763          72 :     foreach(cell, istmt->objects)
    2764             :     {
    2765          38 :         Oid         loid = lfirst_oid(cell);
    2766             :         Form_pg_largeobject_metadata form_lo_meta;
    2767             :         char        loname[NAMEDATALEN];
    2768             :         Datum       aclDatum;
    2769             :         bool        isNull;
    2770             :         AclMode     avail_goptions;
    2771             :         AclMode     this_privileges;
    2772             :         Acl        *old_acl;
    2773             :         Acl        *new_acl;
    2774             :         Oid         grantorId;
    2775             :         Oid         ownerId;
    2776             :         HeapTuple   newtuple;
    2777             :         Datum       values[Natts_pg_largeobject_metadata];
    2778             :         bool        nulls[Natts_pg_largeobject_metadata];
    2779             :         bool        replaces[Natts_pg_largeobject_metadata];
    2780             :         int         noldmembers;
    2781             :         int         nnewmembers;
    2782             :         Oid        *oldmembers;
    2783             :         Oid        *newmembers;
    2784             :         ScanKeyData entry[1];
    2785             :         SysScanDesc scan;
    2786             :         HeapTuple   tuple;
    2787             : 
    2788             :         /* There's no syscache for pg_largeobject_metadata */
    2789          38 :         ScanKeyInit(&entry[0],
    2790             :                     Anum_pg_largeobject_metadata_oid,
    2791             :                     BTEqualStrategyNumber, F_OIDEQ,
    2792             :                     ObjectIdGetDatum(loid));
    2793             : 
    2794          38 :         scan = systable_beginscan(relation,
    2795             :                                   LargeObjectMetadataOidIndexId, true,
    2796             :                                   NULL, 1, entry);
    2797             : 
    2798          38 :         tuple = systable_getnext(scan);
    2799          38 :         if (!HeapTupleIsValid(tuple))
    2800           0 :             elog(ERROR, "could not find tuple for large object %u", loid);
    2801             : 
    2802          38 :         form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
    2803             : 
    2804             :         /*
    2805             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2806             :          * substitute the proper default.
    2807             :          */
    2808          38 :         ownerId = form_lo_meta->lomowner;
    2809          38 :         aclDatum = heap_getattr(tuple,
    2810             :                                 Anum_pg_largeobject_metadata_lomacl,
    2811             :                                 RelationGetDescr(relation), &isNull);
    2812          38 :         if (isNull)
    2813             :         {
    2814          26 :             old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    2815             :             /* There are no old member roles according to the catalogs */
    2816          26 :             noldmembers = 0;
    2817          26 :             oldmembers = NULL;
    2818             :         }
    2819             :         else
    2820             :         {
    2821          12 :             old_acl = DatumGetAclPCopy(aclDatum);
    2822             :             /* Get the roles mentioned in the existing ACL */
    2823          12 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2824             :         }
    2825             : 
    2826             :         /* Determine ID to do the grant as, and available grant options */
    2827          38 :         select_best_grantor(GetUserId(), istmt->privileges,
    2828             :                             old_acl, ownerId,
    2829             :                             &grantorId, &avail_goptions);
    2830             : 
    2831             :         /*
    2832             :          * Restrict the privileges to what we can actually grant, and emit the
    2833             :          * standards-mandated warning and error messages.
    2834             :          */
    2835          38 :         snprintf(loname, sizeof(loname), "large object %u", loid);
    2836          38 :         this_privileges =
    2837          76 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2838          38 :                                      istmt->all_privs, istmt->privileges,
    2839             :                                      loid, grantorId, OBJECT_LARGEOBJECT,
    2840             :                                      loname, 0, NULL);
    2841             : 
    2842             :         /*
    2843             :          * Generate new ACL.
    2844             :          */
    2845          76 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2846          38 :                                        istmt->grant_option, istmt->behavior,
    2847             :                                        istmt->grantees, this_privileges,
    2848             :                                        grantorId, ownerId);
    2849             : 
    2850             :         /*
    2851             :          * We need the members of both old and new ACLs so we can correct the
    2852             :          * shared dependency information.
    2853             :          */
    2854          38 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2855             : 
    2856             :         /* finished building new ACL value, now insert it */
    2857          38 :         MemSet(values, 0, sizeof(values));
    2858          38 :         MemSet(nulls, false, sizeof(nulls));
    2859          38 :         MemSet(replaces, false, sizeof(replaces));
    2860             : 
    2861          38 :         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
    2862             :         values[Anum_pg_largeobject_metadata_lomacl - 1]
    2863          38 :             = PointerGetDatum(new_acl);
    2864             : 
    2865          38 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2866             :                                      values, nulls, replaces);
    2867             : 
    2868          38 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2869             : 
    2870             :         /* Update initial privileges for extensions */
    2871          38 :         recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
    2872             : 
    2873             :         /* Update the shared dependency ACL info */
    2874          38 :         updateAclDependencies(LargeObjectRelationId,
    2875             :                               form_lo_meta->oid, 0,
    2876             :                               ownerId,
    2877             :                               noldmembers, oldmembers,
    2878             :                               nnewmembers, newmembers);
    2879             : 
    2880          38 :         systable_endscan(scan);
    2881             : 
    2882          38 :         pfree(new_acl);
    2883             : 
    2884             :         /* prevent error when processing duplicate objects */
    2885          38 :         CommandCounterIncrement();
    2886             :     }
    2887             : 
    2888          34 :     table_close(relation, RowExclusiveLock);
    2889          34 : }
    2890             : 
    2891             : static void
    2892        1028 : ExecGrant_Namespace(InternalGrant *istmt)
    2893             : {
    2894             :     Relation    relation;
    2895             :     ListCell   *cell;
    2896             : 
    2897        1028 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2898          24 :         istmt->privileges = ACL_ALL_RIGHTS_SCHEMA;
    2899             : 
    2900        1028 :     relation = table_open(NamespaceRelationId, RowExclusiveLock);
    2901             : 
    2902        2060 :     foreach(cell, istmt->objects)
    2903             :     {
    2904        1032 :         Oid         nspid = lfirst_oid(cell);
    2905             :         Form_pg_namespace pg_namespace_tuple;
    2906             :         Datum       aclDatum;
    2907             :         bool        isNull;
    2908             :         AclMode     avail_goptions;
    2909             :         AclMode     this_privileges;
    2910             :         Acl        *old_acl;
    2911             :         Acl        *new_acl;
    2912             :         Oid         grantorId;
    2913             :         Oid         ownerId;
    2914             :         HeapTuple   tuple;
    2915             :         HeapTuple   newtuple;
    2916             :         Datum       values[Natts_pg_namespace];
    2917             :         bool        nulls[Natts_pg_namespace];
    2918             :         bool        replaces[Natts_pg_namespace];
    2919             :         int         noldmembers;
    2920             :         int         nnewmembers;
    2921             :         Oid        *oldmembers;
    2922             :         Oid        *newmembers;
    2923             : 
    2924        1032 :         tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
    2925        1032 :         if (!HeapTupleIsValid(tuple))
    2926           0 :             elog(ERROR, "cache lookup failed for namespace %u", nspid);
    2927             : 
    2928        1032 :         pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
    2929             : 
    2930             :         /*
    2931             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2932             :          * substitute the proper default.
    2933             :          */
    2934        1032 :         ownerId = pg_namespace_tuple->nspowner;
    2935        1032 :         aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
    2936             :                                    Anum_pg_namespace_nspacl,
    2937             :                                    &isNull);
    2938        1032 :         if (isNull)
    2939             :         {
    2940        1020 :             old_acl = acldefault(OBJECT_SCHEMA, ownerId);
    2941             :             /* There are no old member roles according to the catalogs */
    2942        1020 :             noldmembers = 0;
    2943        1020 :             oldmembers = NULL;
    2944             :         }
    2945             :         else
    2946             :         {
    2947          12 :             old_acl = DatumGetAclPCopy(aclDatum);
    2948             :             /* Get the roles mentioned in the existing ACL */
    2949          12 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2950             :         }
    2951             : 
    2952             :         /* Determine ID to do the grant as, and available grant options */
    2953        1032 :         select_best_grantor(GetUserId(), istmt->privileges,
    2954             :                             old_acl, ownerId,
    2955             :                             &grantorId, &avail_goptions);
    2956             : 
    2957             :         /*
    2958             :          * Restrict the privileges to what we can actually grant, and emit the
    2959             :          * standards-mandated warning and error messages.
    2960             :          */
    2961        1032 :         this_privileges =
    2962        2064 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2963        1032 :                                      istmt->all_privs, istmt->privileges,
    2964             :                                      nspid, grantorId, OBJECT_SCHEMA,
    2965        1032 :                                      NameStr(pg_namespace_tuple->nspname),
    2966             :                                      0, NULL);
    2967             : 
    2968             :         /*
    2969             :          * Generate new ACL.
    2970             :          */
    2971        2064 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2972        1032 :                                        istmt->grant_option, istmt->behavior,
    2973             :                                        istmt->grantees, this_privileges,
    2974             :                                        grantorId, ownerId);
    2975             : 
    2976             :         /*
    2977             :          * We need the members of both old and new ACLs so we can correct the
    2978             :          * shared dependency information.
    2979             :          */
    2980        1032 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2981             : 
    2982             :         /* finished building new ACL value, now insert it */
    2983        1032 :         MemSet(values, 0, sizeof(values));
    2984        1032 :         MemSet(nulls, false, sizeof(nulls));
    2985        1032 :         MemSet(replaces, false, sizeof(replaces));
    2986             : 
    2987        1032 :         replaces[Anum_pg_namespace_nspacl - 1] = true;
    2988        1032 :         values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
    2989             : 
    2990        1032 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2991             :                                      nulls, replaces);
    2992             : 
    2993        1032 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2994             : 
    2995             :         /* Update initial privileges for extensions */
    2996        1032 :         recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
    2997             : 
    2998             :         /* Update the shared dependency ACL info */
    2999        1032 :         updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0,
    3000             :                               ownerId,
    3001             :                               noldmembers, oldmembers,
    3002             :                               nnewmembers, newmembers);
    3003             : 
    3004        1032 :         ReleaseSysCache(tuple);
    3005             : 
    3006        1032 :         pfree(new_acl);
    3007             : 
    3008             :         /* prevent error when processing duplicate objects */
    3009        1032 :         CommandCounterIncrement();
    3010             :     }
    3011             : 
    3012        1028 :     table_close(relation, RowExclusiveLock);
    3013        1028 : }
    3014             : 
    3015             : static void
    3016           0 : ExecGrant_Tablespace(InternalGrant *istmt)
    3017             : {
    3018             :     Relation    relation;
    3019             :     ListCell   *cell;
    3020             : 
    3021           0 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    3022           0 :         istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
    3023             : 
    3024           0 :     relation = table_open(TableSpaceRelationId, RowExclusiveLock);
    3025             : 
    3026           0 :     foreach(cell, istmt->objects)
    3027             :     {
    3028           0 :         Oid         tblId = lfirst_oid(cell);
    3029             :         Form_pg_tablespace pg_tablespace_tuple;
    3030             :         Datum       aclDatum;
    3031             :         bool        isNull;
    3032             :         AclMode     avail_goptions;
    3033             :         AclMode     this_privileges;
    3034             :         Acl        *old_acl;
    3035             :         Acl        *new_acl;
    3036             :         Oid         grantorId;
    3037             :         Oid         ownerId;
    3038             :         HeapTuple   newtuple;
    3039             :         Datum       values[Natts_pg_tablespace];
    3040             :         bool        nulls[Natts_pg_tablespace];
    3041             :         bool        replaces[Natts_pg_tablespace];
    3042             :         int         noldmembers;
    3043             :         int         nnewmembers;
    3044             :         Oid        *oldmembers;
    3045             :         Oid        *newmembers;
    3046             :         HeapTuple   tuple;
    3047             : 
    3048             :         /* Search syscache for pg_tablespace */
    3049           0 :         tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
    3050           0 :         if (!HeapTupleIsValid(tuple))
    3051           0 :             elog(ERROR, "cache lookup failed for tablespace %u", tblId);
    3052             : 
    3053           0 :         pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
    3054             : 
    3055             :         /*
    3056             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    3057             :          * substitute the proper default.
    3058             :          */
    3059           0 :         ownerId = pg_tablespace_tuple->spcowner;
    3060           0 :         aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
    3061             :                                 RelationGetDescr(relation), &isNull);
    3062           0 :         if (isNull)
    3063             :         {
    3064           0 :             old_acl = acldefault(OBJECT_TABLESPACE, ownerId);
    3065             :             /* There are no old member roles according to the catalogs */
    3066           0 :             noldmembers = 0;
    3067           0 :             oldmembers = NULL;
    3068             :         }
    3069             :         else
    3070             :         {
    3071           0 :             old_acl = DatumGetAclPCopy(aclDatum);
    3072             :             /* Get the roles mentioned in the existing ACL */
    3073           0 :             noldmembers = aclmembers(old_acl, &oldmembers);
    3074             :         }
    3075             : 
    3076             :         /* Determine ID to do the grant as, and available grant options */
    3077           0 :         select_best_grantor(GetUserId(), istmt->privileges,
    3078             :                             old_acl, ownerId,
    3079             :                             &grantorId, &avail_goptions);
    3080             : 
    3081             :         /*
    3082             :          * Restrict the privileges to what we can actually grant, and emit the
    3083             :          * standards-mandated warning and error messages.
    3084             :          */
    3085           0 :         this_privileges =
    3086           0 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    3087           0 :                                      istmt->all_privs, istmt->privileges,
    3088             :                                      tblId, grantorId, OBJECT_TABLESPACE,
    3089           0 :                                      NameStr(pg_tablespace_tuple->spcname),
    3090             :                                      0, NULL);
    3091             : 
    3092             :         /*
    3093             :          * Generate new ACL.
    3094             :          */
    3095           0 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    3096           0 :                                        istmt->grant_option, istmt->behavior,
    3097             :                                        istmt->grantees, this_privileges,
    3098             :                                        grantorId, ownerId);
    3099             : 
    3100             :         /*
    3101             :          * We need the members of both old and new ACLs so we can correct the
    3102             :          * shared dependency information.
    3103             :          */
    3104           0 :         nnewmembers = aclmembers(new_acl, &newmembers);
    3105             : 
    3106             :         /* finished building new ACL value, now insert it */
    3107           0 :         MemSet(values, 0, sizeof(values));
    3108           0 :         MemSet(nulls, false, sizeof(nulls));
    3109           0 :         MemSet(replaces, false, sizeof(replaces));
    3110             : 
    3111           0 :         replaces[Anum_pg_tablespace_spcacl - 1] = true;
    3112           0 :         values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
    3113             : 
    3114           0 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    3115             :                                      nulls, replaces);
    3116             : 
    3117           0 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    3118             : 
    3119             :         /* Update the shared dependency ACL info */
    3120           0 :         updateAclDependencies(TableSpaceRelationId, tblId, 0,
    3121             :                               ownerId,
    3122             :                               noldmembers, oldmembers,
    3123             :                               nnewmembers, newmembers);
    3124             : 
    3125           0 :         ReleaseSysCache(tuple);
    3126           0 :         pfree(new_acl);
    3127             : 
    3128             :         /* prevent error when processing duplicate objects */
    3129           0 :         CommandCounterIncrement();
    3130             :     }
    3131             : 
    3132           0 :     table_close(relation, RowExclusiveLock);
    3133           0 : }
    3134             : 
    3135             : static void
    3136          74 : ExecGrant_Type(InternalGrant *istmt)
    3137             : {
    3138             :     Relation    relation;
    3139             :     ListCell   *cell;
    3140             : 
    3141          74 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    3142           8 :         istmt->privileges = ACL_ALL_RIGHTS_TYPE;
    3143             : 
    3144          74 :     relation = table_open(TypeRelationId, RowExclusiveLock);
    3145             : 
    3146         136 :     foreach(cell, istmt->objects)
    3147             :     {
    3148          74 :         Oid         typId = lfirst_oid(cell);
    3149             :         Form_pg_type pg_type_tuple;
    3150             :         Datum       aclDatum;
    3151             :         bool        isNull;
    3152             :         AclMode     avail_goptions;
    3153             :         AclMode     this_privileges;
    3154             :         Acl        *old_acl;
    3155             :         Acl        *new_acl;
    3156             :         Oid         grantorId;
    3157             :         Oid         ownerId;
    3158             :         HeapTuple   newtuple;
    3159             :         Datum       values[Natts_pg_type];
    3160             :         bool        nulls[Natts_pg_type];
    3161             :         bool        replaces[Natts_pg_type];
    3162             :         int         noldmembers;
    3163             :         int         nnewmembers;
    3164             :         Oid        *oldmembers;
    3165             :         Oid        *newmembers;
    3166             :         HeapTuple   tuple;
    3167             : 
    3168             :         /* Search syscache for pg_type */
    3169          74 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
    3170          74 :         if (!HeapTupleIsValid(tuple))
    3171           0 :             elog(ERROR, "cache lookup failed for type %u", typId);
    3172             : 
    3173          74 :         pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
    3174             : 
    3175          74 :         if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
    3176           4 :             ereport(ERROR,
    3177             :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    3178             :                      errmsg("cannot set privileges of array types"),
    3179             :                      errhint("Set the privileges of the element type instead.")));
    3180             : 
    3181             :         /* Used GRANT DOMAIN on a non-domain? */
    3182          84 :         if (istmt->objtype == OBJECT_DOMAIN &&
    3183          14 :             pg_type_tuple->typtype != TYPTYPE_DOMAIN)
    3184           4 :             ereport(ERROR,
    3185             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3186             :                      errmsg("\"%s\" is not a domain",
    3187             :                             NameStr(pg_type_tuple->typname))));
    3188             : 
    3189             :         /*
    3190             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    3191             :          * substitute the proper default.
    3192             :          */
    3193          66 :         ownerId = pg_type_tuple->typowner;
    3194          66 :         aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
    3195             :                                 RelationGetDescr(relation), &isNull);
    3196          66 :         if (isNull)
    3197             :         {
    3198          34 :             old_acl = acldefault(istmt->objtype, ownerId);
    3199             :             /* There are no old member roles according to the catalogs */
    3200          34 :             noldmembers = 0;
    3201          34 :             oldmembers = NULL;
    3202             :         }
    3203             :         else
    3204             :         {
    3205          32 :             old_acl = DatumGetAclPCopy(aclDatum);
    3206             :             /* Get the roles mentioned in the existing ACL */
    3207          32 :             noldmembers = aclmembers(old_acl, &oldmembers);
    3208             :         }
    3209             : 
    3210             :         /* Determine ID to do the grant as, and available grant options */
    3211          66 :         select_best_grantor(GetUserId(), istmt->privileges,
    3212             :                             old_acl, ownerId,
    3213             :                             &grantorId, &avail_goptions);
    3214             : 
    3215             :         /*
    3216             :          * Restrict the privileges to what we can actually grant, and emit the
    3217             :          * standards-mandated warning and error messages.
    3218             :          */
    3219          66 :         this_privileges =
    3220         132 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    3221          66 :                                      istmt->all_privs, istmt->privileges,
    3222             :                                      typId, grantorId, OBJECT_TYPE,
    3223          66 :                                      NameStr(pg_type_tuple->typname),
    3224             :                                      0, NULL);
    3225             : 
    3226             :         /*
    3227             :          * Generate new ACL.
    3228             :          */
    3229         124 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    3230          62 :                                        istmt->grant_option, istmt->behavior,
    3231             :                                        istmt->grantees, this_privileges,
    3232             :                                        grantorId, ownerId);
    3233             : 
    3234             :         /*
    3235             :          * We need the members of both old and new ACLs so we can correct the
    3236             :          * shared dependency information.
    3237             :          */
    3238          62 :         nnewmembers = aclmembers(new_acl, &newmembers);
    3239             : 
    3240             :         /* finished building new ACL value, now insert it */
    3241          62 :         MemSet(values, 0, sizeof(values));
    3242          62 :         MemSet(nulls, false, sizeof(nulls));
    3243          62 :         MemSet(replaces, false, sizeof(replaces));
    3244             : 
    3245          62 :         replaces[Anum_pg_type_typacl - 1] = true;
    3246          62 :         values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
    3247             : 
    3248          62 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    3249             :                                      nulls, replaces);
    3250             : 
    3251          62 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    3252             : 
    3253             :         /* Update initial privileges for extensions */
    3254          62 :         recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
    3255             : 
    3256             :         /* Update the shared dependency ACL info */
    3257          62 :         updateAclDependencies(TypeRelationId, typId, 0,
    3258             :                               ownerId,
    3259             :                               noldmembers, oldmembers,
    3260             :                               nnewmembers, newmembers);
    3261             : 
    3262          62 :         ReleaseSysCache(tuple);
    3263          62 :         pfree(new_acl);
    3264             : 
    3265             :         /* prevent error when processing duplicate objects */
    3266          62 :         CommandCounterIncrement();
    3267             :     }
    3268             : 
    3269          62 :     table_close(relation, RowExclusiveLock);
    3270          62 : }
    3271             : 
    3272             : 
    3273             : static AclMode
    3274       37000 : string_to_privilege(const char *privname)
    3275             : {
    3276       37000 :     if (strcmp(privname, "insert") == 0)
    3277         102 :         return ACL_INSERT;
    3278       36898 :     if (strcmp(privname, "select") == 0)
    3279       19778 :         return ACL_SELECT;
    3280       17120 :     if (strcmp(privname, "update") == 0)
    3281         408 :         return ACL_UPDATE;
    3282       16712 :     if (strcmp(privname, "delete") == 0)
    3283          48 :         return ACL_DELETE;
    3284       16664 :     if (strcmp(privname, "truncate") == 0)
    3285          24 :         return ACL_TRUNCATE;
    3286       16640 :     if (strcmp(privname, "references") == 0)
    3287           8 :         return ACL_REFERENCES;
    3288       16632 :     if (strcmp(privname, "trigger") == 0)
    3289           4 :         return ACL_TRIGGER;
    3290       16628 :     if (strcmp(privname, "execute") == 0)
    3291       13738 :         return ACL_EXECUTE;
    3292        2890 :     if (strcmp(privname, "usage") == 0)
    3293        1256 :         return ACL_USAGE;
    3294        1634 :     if (strcmp(privname, "create") == 0)
    3295         982 :         return ACL_CREATE;
    3296         652 :     if (strcmp(privname, "temporary") == 0)
    3297         646 :         return ACL_CREATE_TEMP;
    3298           6 :     if (strcmp(privname, "temp") == 0)
    3299           0 :         return ACL_CREATE_TEMP;
    3300           6 :     if (strcmp(privname, "connect") == 0)
    3301           6 :         return ACL_CONNECT;
    3302           0 :     if (strcmp(privname, "rule") == 0)
    3303           0 :         return 0;               /* ignore old RULE privileges */
    3304           0 :     ereport(ERROR,
    3305             :             (errcode(ERRCODE_SYNTAX_ERROR),
    3306             :              errmsg("unrecognized privilege type \"%s\"", privname)));
    3307             :     return 0;                   /* appease compiler */
    3308             : }
    3309             : 
    3310             : static const char *
    3311          16 : privilege_to_string(AclMode privilege)
    3312             : {
    3313          16 :     switch (privilege)
    3314             :     {
    3315             :         case ACL_INSERT:
    3316           4 :             return "INSERT";
    3317             :         case ACL_SELECT:
    3318           0 :             return "SELECT";
    3319             :         case ACL_UPDATE:
    3320           0 :             return "UPDATE";
    3321             :         case ACL_DELETE:
    3322           0 :             return "DELETE";
    3323             :         case ACL_TRUNCATE:
    3324           0 :             return "TRUNCATE";
    3325             :         case ACL_REFERENCES:
    3326           0 :             return "REFERENCES";
    3327             :         case ACL_TRIGGER:
    3328           0 :             return "TRIGGER";
    3329             :         case ACL_EXECUTE:
    3330           0 :             return "EXECUTE";
    3331             :         case ACL_USAGE:
    3332          12 :             return "USAGE";
    3333             :         case ACL_CREATE:
    3334           0 :             return "CREATE";
    3335             :         case ACL_CREATE_TEMP:
    3336           0 :             return "TEMP";
    3337             :         case ACL_CONNECT:
    3338           0 :             return "CONNECT";
    3339             :         default:
    3340           0 :             elog(ERROR, "unrecognized privilege: %d", (int) privilege);
    3341             :     }
    3342             :     return NULL;                /* appease compiler */
    3343             : }
    3344             : 
    3345             : /*
    3346             :  * Standardized reporting of aclcheck permissions failures.
    3347             :  *
    3348             :  * Note: we do not double-quote the %s's below, because many callers
    3349             :  * supply strings that might be already quoted.
    3350             :  */
    3351             : void
    3352        1036 : aclcheck_error(AclResult aclerr, ObjectType objtype,
    3353             :                const char *objectname)
    3354             : {
    3355        1036 :     switch (aclerr)
    3356             :     {
    3357             :         case ACLCHECK_OK:
    3358             :             /* no error, so return to caller */
    3359           0 :             break;
    3360             :         case ACLCHECK_NO_PRIV:
    3361             :             {
    3362         736 :                 const char *msg = "???";
    3363             : 
    3364         736 :                 switch (objtype)
    3365             :                 {
    3366             :                     case OBJECT_AGGREGATE:
    3367           4 :                         msg = gettext_noop("permission denied for aggregate %s");
    3368           4 :                         break;
    3369             :                     case OBJECT_COLLATION:
    3370           0 :                         msg = gettext_noop("permission denied for collation %s");
    3371           0 :                         break;
    3372             :                     case OBJECT_COLUMN:
    3373           0 :                         msg = gettext_noop("permission denied for column %s");
    3374           0 :                         break;
    3375             :                     case OBJECT_CONVERSION:
    3376           0 :                         msg = gettext_noop("permission denied for conversion %s");
    3377           0 :                         break;
    3378             :                     case OBJECT_DATABASE:
    3379           4 :                         msg = gettext_noop("permission denied for database %s");
    3380           4 :                         break;
    3381             :                     case OBJECT_DOMAIN:
    3382           0 :                         msg = gettext_noop("permission denied for domain %s");
    3383           0 :                         break;
    3384             :                     case OBJECT_EVENT_TRIGGER:
    3385           0 :                         msg = gettext_noop("permission denied for event trigger %s");
    3386           0 :                         break;
    3387             :                     case OBJECT_EXTENSION:
    3388           0 :                         msg = gettext_noop("permission denied for extension %s");
    3389           0 :                         break;
    3390             :                     case OBJECT_FDW:
    3391          30 :                         msg = gettext_noop("permission denied for foreign-data wrapper %s");
    3392          30 :                         break;
    3393             :                     case OBJECT_FOREIGN_SERVER:
    3394          14 :                         msg = gettext_noop("permission denied for foreign server %s");
    3395          14 :                         break;
    3396             :                     case OBJECT_FOREIGN_TABLE:
    3397           2 :                         msg = gettext_noop("permission denied for foreign table %s");
    3398           2 :                         break;
    3399             :                     case OBJECT_FUNCTION:
    3400          44 :                         msg = gettext_noop("permission denied for function %s");
    3401          44 :                         break;
    3402             :                     case OBJECT_INDEX:
    3403           0 :                         msg = gettext_noop("permission denied for index %s");
    3404           0 :                         break;
    3405             :                     case OBJECT_LANGUAGE:
    3406           4 :                         msg = gettext_noop("permission denied for language %s");
    3407           4 :                         break;
    3408             :                     case OBJECT_LARGEOBJECT:
    3409           0 :                         msg = gettext_noop("permission denied for large object %s");
    3410           0 :                         break;
    3411             :                     case OBJECT_MATVIEW:
    3412           0 :                         msg = gettext_noop("permission denied for materialized view %s");
    3413           0 :                         break;
    3414             :                     case OBJECT_OPCLASS:
    3415           0 :                         msg = gettext_noop("permission denied for operator class %s");
    3416           0 :                         break;
    3417             :                     case OBJECT_OPERATOR:
    3418           0 :                         msg = gettext_noop("permission denied for operator %s");
    3419           0 :                         break;
    3420             :                     case OBJECT_OPFAMILY:
    3421           0 :                         msg = gettext_noop("permission denied for operator family %s");
    3422           0 :                         break;
    3423             :                     case OBJECT_POLICY:
    3424           0 :                         msg = gettext_noop("permission denied for policy %s");
    3425           0 :                         break;
    3426             :                     case OBJECT_PROCEDURE:
    3427           8 :                         msg = gettext_noop("permission denied for procedure %s");
    3428           8 :                         break;
    3429             :                     case OBJECT_PUBLICATION:
    3430           0 :                         msg = gettext_noop("permission denied for publication %s");
    3431           0 :                         break;
    3432             :                     case OBJECT_ROUTINE:
    3433           0 :                         msg = gettext_noop("permission denied for routine %s");
    3434           0 :                         break;
    3435             :                     case OBJECT_SCHEMA:
    3436          10 :                         msg = gettext_noop("permission denied for schema %s");
    3437          10 :                         break;
    3438             :                     case OBJECT_SEQUENCE:
    3439           0 :                         msg = gettext_noop("permission denied for sequence %s");
    3440           0 :                         break;
    3441             :                     case OBJECT_STATISTIC_EXT:
    3442           0 :                         msg = gettext_noop("permission denied for statistics object %s");
    3443           0 :                         break;
    3444             :                     case OBJECT_SUBSCRIPTION:
    3445           0 :                         msg = gettext_noop("permission denied for subscription %s");
    3446           0 :                         break;
    3447             :                     case OBJECT_TABLE:
    3448         440 :                         msg = gettext_noop("permission denied for table %s");
    3449         440 :                         break;
    3450             :                     case OBJECT_TABLESPACE:
    3451           4 :                         msg = gettext_noop("permission denied for tablespace %s");
    3452           4 :                         break;
    3453             :                     case OBJECT_TSCONFIGURATION:
    3454           0 :                         msg = gettext_noop("permission denied for text search configuration %s");
    3455           0 :                         break;
    3456             :                     case OBJECT_TSDICTIONARY:
    3457           0 :                         msg = gettext_noop("permission denied for text search dictionary %s");
    3458           0 :                         break;
    3459             :                     case OBJECT_TYPE:
    3460          76 :                         msg = gettext_noop("permission denied for type %s");
    3461          76 :                         break;
    3462             :                     case OBJECT_VIEW:
    3463          96 :                         msg = gettext_noop("permission denied for view %s");
    3464          96 :                         break;
    3465             :                         /* these currently aren't used */
    3466             :                     case OBJECT_ACCESS_METHOD:
    3467             :                     case OBJECT_AMOP:
    3468             :                     case OBJECT_AMPROC:
    3469             :                     case OBJECT_ATTRIBUTE:
    3470             :                     case OBJECT_CAST:
    3471             :                     case OBJECT_DEFAULT:
    3472             :                     case OBJECT_DEFACL:
    3473             :                     case OBJECT_DOMCONSTRAINT:
    3474             :                     case OBJECT_PUBLICATION_REL:
    3475             :                     case OBJECT_ROLE:
    3476             :                     case OBJECT_RULE:
    3477             :                     case OBJECT_TABCONSTRAINT:
    3478             :                     case OBJECT_TRANSFORM:
    3479             :                     case OBJECT_TRIGGER:
    3480             :                     case OBJECT_TSPARSER:
    3481             :                     case OBJECT_TSTEMPLATE:
    3482             :                     case OBJECT_USER_MAPPING:
    3483           0 :                         elog(ERROR, "unsupported object type %d", objtype);
    3484             :                 }
    3485             : 
    3486         736 :                 ereport(ERROR,
    3487             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3488             :                          errmsg(msg, objectname)));
    3489             :                 break;
    3490             :             }
    3491             :         case ACLCHECK_NOT_OWNER:
    3492             :             {
    3493         300 :                 const char *msg = "???";
    3494             : 
    3495         300 :                 switch (objtype)
    3496             :                 {
    3497             :                     case OBJECT_AGGREGATE:
    3498           4 :                         msg = gettext_noop("must be owner of aggregate %s");
    3499           4 :                         break;
    3500             :                     case OBJECT_COLLATION:
    3501           0 :                         msg = gettext_noop("must be owner of collation %s");
    3502           0 :                         break;
    3503             :                     case OBJECT_CONVERSION:
    3504          12 :                         msg = gettext_noop("must be owner of conversion %s");
    3505          12 :                         break;
    3506             :                     case OBJECT_DATABASE:
    3507           0 :                         msg = gettext_noop("must be owner of database %s");
    3508           0 :                         break;
    3509             :                     case OBJECT_DOMAIN:
    3510           0 :                         msg = gettext_noop("must be owner of domain %s");
    3511           0 :                         break;
    3512             :                     case OBJECT_EVENT_TRIGGER:
    3513           0 :                         msg = gettext_noop("must be owner of event trigger %s");
    3514           0 :                         break;
    3515             :                     case OBJECT_EXTENSION:
    3516           0 :                         msg = gettext_noop("must be owner of extension %s");
    3517           0 :                         break;
    3518             :                     case OBJECT_FDW:
    3519          12 :                         msg = gettext_noop("must be owner of foreign-data wrapper %s");
    3520          12 :                         break;
    3521             :                     case OBJECT_FOREIGN_SERVER:
    3522          76 :                         msg = gettext_noop("must be owner of foreign server %s");
    3523          76 :                         break;
    3524             :                     case OBJECT_FOREIGN_TABLE:
    3525           0 :                         msg = gettext_noop("must be owner of foreign table %s");
    3526           0 :                         break;
    3527             :                     case OBJECT_FUNCTION:
    3528          28 :                         msg = gettext_noop("must be owner of function %s");
    3529          28 :                         break;
    3530             :                     case OBJECT_INDEX:
    3531          16 :                         msg = gettext_noop("must be owner of index %s");
    3532          16 :                         break;
    3533             :                     case OBJECT_LANGUAGE:
    3534           8 :                         msg = gettext_noop("must be owner of language %s");
    3535           8 :                         break;
    3536             :                     case OBJECT_LARGEOBJECT:
    3537           0 :                         msg = gettext_noop("must be owner of large object %s");
    3538           0 :                         break;
    3539             :                     case OBJECT_MATVIEW:
    3540           0 :                         msg = gettext_noop("must be owner of materialized view %s");
    3541           0 :                         break;
    3542             :                     case OBJECT_OPCLASS:
    3543          12 :                         msg = gettext_noop("must be owner of operator class %s");
    3544          12 :                         break;
    3545             :                     case OBJECT_OPERATOR:
    3546          12 :                         msg = gettext_noop("must be owner of operator %s");
    3547          12 :                         break;
    3548             :                     case OBJECT_OPFAMILY:
    3549          12 :                         msg = gettext_noop("must be owner of operator family %s");
    3550          12 :                         break;
    3551             :                     case OBJECT_PROCEDURE:
    3552           4 :                         msg = gettext_noop("must be owner of procedure %s");
    3553           4 :                         break;
    3554             :                     case OBJECT_PUBLICATION:
    3555           4 :                         msg = gettext_noop("must be owner of publication %s");
    3556           4 :                         break;
    3557             :                     case OBJECT_ROUTINE:
    3558           0 :                         msg = gettext_noop("must be owner of routine %s");
    3559           0 :                         break;
    3560             :                     case OBJECT_SEQUENCE:
    3561           4 :                         msg = gettext_noop("must be owner of sequence %s");
    3562           4 :                         break;
    3563             :                     case OBJECT_SUBSCRIPTION:
    3564           4 :                         msg = gettext_noop("must be owner of subscription %s");
    3565           4 :                         break;
    3566             :                     case OBJECT_TABLE:
    3567          32 :                         msg = gettext_noop("must be owner of table %s");
    3568          32 :                         break;
    3569             :                     case OBJECT_TYPE:
    3570           4 :                         msg = gettext_noop("must be owner of type %s");
    3571           4 :                         break;
    3572             :                     case OBJECT_VIEW:
    3573           4 :                         msg = gettext_noop("must be owner of view %s");
    3574           4 :                         break;
    3575             :                     case OBJECT_SCHEMA:
    3576           4 :                         msg = gettext_noop("must be owner of schema %s");
    3577           4 :                         break;
    3578             :                     case OBJECT_STATISTIC_EXT:
    3579          12 :                         msg = gettext_noop("must be owner of statistics object %s");
    3580          12 :                         break;
    3581             :                     case OBJECT_TABLESPACE:
    3582           0 :                         msg = gettext_noop("must be owner of tablespace %s");
    3583           0 :                         break;
    3584             :                     case OBJECT_TSCONFIGURATION:
    3585          12 :                         msg = gettext_noop("must be owner of text search configuration %s");
    3586          12 :                         break;
    3587             :                     case OBJECT_TSDICTIONARY:
    3588          12 :                         msg = gettext_noop("must be owner of text search dictionary %s");
    3589          12 :                         break;
    3590             : 
    3591             :                         /*
    3592             :                          * Special cases: For these, the error message talks
    3593             :                          * about "relation", because that's where the
    3594             :                          * ownership is attached.  See also
    3595             :                          * check_object_ownership().
    3596             :                          */
    3597             :                     case OBJECT_COLUMN:
    3598             :                     case OBJECT_POLICY:
    3599             :                     case OBJECT_RULE:
    3600             :                     case OBJECT_TABCONSTRAINT:
    3601             :                     case OBJECT_TRIGGER:
    3602          12 :                         msg = gettext_noop("must be owner of relation %s");
    3603          12 :                         break;
    3604             :                         /* these currently aren't used */
    3605             :                     case OBJECT_ACCESS_METHOD:
    3606             :                     case OBJECT_AMOP:
    3607             :                     case OBJECT_AMPROC:
    3608             :                     case OBJECT_ATTRIBUTE:
    3609             :                     case OBJECT_CAST:
    3610             :                     case OBJECT_DEFAULT:
    3611             :                     case OBJECT_DEFACL:
    3612             :                     case OBJECT_DOMCONSTRAINT:
    3613             :                     case OBJECT_PUBLICATION_REL:
    3614             :                     case OBJECT_ROLE:
    3615             :                     case OBJECT_TRANSFORM:
    3616             :                     case OBJECT_TSPARSER:
    3617             :                     case OBJECT_TSTEMPLATE:
    3618             :                     case OBJECT_USER_MAPPING:
    3619           0 :                         elog(ERROR, "unsupported object type %d", objtype);
    3620             :                 }
    3621             : 
    3622         300 :                 ereport(ERROR,
    3623             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3624             :                          errmsg(msg, objectname)));
    3625             :                 break;
    3626             :             }
    3627             :         default:
    3628           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    3629             :             break;
    3630             :     }
    3631           0 : }
    3632             : 
    3633             : 
    3634             : void
    3635           0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
    3636             :                    const char *objectname, const char *colname)
    3637             : {
    3638           0 :     switch (aclerr)
    3639             :     {
    3640             :         case ACLCHECK_OK:
    3641             :             /* no error, so return to caller */
    3642           0 :             break;
    3643             :         case ACLCHECK_NO_PRIV:
    3644           0 :             ereport(ERROR,
    3645             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3646             :                      errmsg("permission denied for column \"%s\" of relation \"%s\"",
    3647             :                             colname, objectname)));
    3648             :             break;
    3649             :         case ACLCHECK_NOT_OWNER:
    3650             :             /* relation msg is OK since columns don't have separate owners */
    3651           0 :             aclcheck_error(aclerr, objtype, objectname);
    3652           0 :             break;
    3653             :         default:
    3654           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    3655             :             break;
    3656             :     }
    3657           0 : }
    3658             : 
    3659             : 
    3660             : /*
    3661             :  * Special common handling for types: use element type instead of array type,
    3662             :  * and format nicely
    3663             :  */
    3664             : void
    3665          76 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
    3666             : {
    3667          76 :     Oid         element_type = get_element_type(typeOid);
    3668             : 
    3669          76 :     aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
    3670           0 : }
    3671             : 
    3672             : 
    3673             : /*
    3674             :  * Relay for the various pg_*_mask routines depending on object kind
    3675             :  */
    3676             : static AclMode
    3677          44 : pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
    3678             :            AclMode mask, AclMaskHow how)
    3679             : {
    3680          44 :     switch (objtype)
    3681             :     {
    3682             :         case OBJECT_COLUMN:
    3683             :             return
    3684           0 :                 pg_class_aclmask(table_oid, roleid, mask, how) |
    3685           0 :                 pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
    3686             :         case OBJECT_TABLE:
    3687             :         case OBJECT_SEQUENCE:
    3688           8 :             return pg_class_aclmask(table_oid, roleid, mask, how);
    3689             :         case OBJECT_DATABASE:
    3690           0 :             return pg_database_aclmask(table_oid, roleid, mask, how);
    3691             :         case OBJECT_FUNCTION:
    3692           0 :             return pg_proc_aclmask(table_oid, roleid, mask, how);
    3693             :         case OBJECT_LANGUAGE:
    3694           4 :             return pg_language_aclmask(table_oid, roleid, mask, how);
    3695             :         case OBJECT_LARGEOBJECT:
    3696           0 :             return pg_largeobject_aclmask_snapshot(table_oid, roleid,
    3697             :                                                    mask, how, NULL);
    3698             :         case OBJECT_SCHEMA:
    3699           0 :             return pg_namespace_aclmask(table_oid, roleid, mask, how);
    3700             :         case OBJECT_STATISTIC_EXT:
    3701           0 :             elog(ERROR, "grantable rights not supported for statistics objects");
    3702             :             /* not reached, but keep compiler quiet */
    3703             :             return ACL_NO_RIGHTS;
    3704             :         case OBJECT_TABLESPACE:
    3705           0 :             return pg_tablespace_aclmask(table_oid, roleid, mask, how);
    3706             :         case OBJECT_FDW:
    3707          12 :             return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
    3708             :         case OBJECT_FOREIGN_SERVER:
    3709          12 :             return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
    3710             :         case OBJECT_EVENT_TRIGGER:
    3711           0 :             elog(ERROR, "grantable rights not supported for event triggers");
    3712             :             /* not reached, but keep compiler quiet */
    3713             :             return ACL_NO_RIGHTS;
    3714             :         case OBJECT_TYPE:
    3715           8 :             return pg_type_aclmask(table_oid, roleid, mask, how);
    3716             :         default:
    3717           0 :             elog(ERROR, "unrecognized objtype: %d",
    3718             :                  (int) objtype);
    3719             :             /* not reached, but keep compiler quiet */
    3720             :             return ACL_NO_RIGHTS;
    3721             :     }
    3722             : }
    3723             : 
    3724             : 
    3725             : /* ****************************************************************
    3726             :  * Exported routines for examining a user's privileges for various objects
    3727             :  *
    3728             :  * See aclmask() for a description of the common API for these functions.
    3729             :  *
    3730             :  * Note: we give lookup failure the full ereport treatment because the
    3731             :  * has_xxx_privilege() family of functions allow users to pass any random
    3732             :  * OID to these functions.
    3733             :  * ****************************************************************
    3734             :  */
    3735             : 
    3736             : /*
    3737             :  * Exported routine for examining a user's privileges for a column
    3738             :  *
    3739             :  * Note: this considers only privileges granted specifically on the column.
    3740             :  * It is caller's responsibility to take relation-level privileges into account
    3741             :  * as appropriate.  (For the same reason, we have no special case for
    3742             :  * superuser-ness here.)
    3743             :  */
    3744             : AclMode
    3745        1242 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
    3746             :                      AclMode mask, AclMaskHow how)
    3747             : {
    3748             :     AclMode     result;
    3749             :     HeapTuple   classTuple;
    3750             :     HeapTuple   attTuple;
    3751             :     Form_pg_class classForm;
    3752             :     Form_pg_attribute attributeForm;
    3753             :     Datum       aclDatum;
    3754             :     bool        isNull;
    3755             :     Acl        *acl;
    3756             :     Oid         ownerId;
    3757             : 
    3758             :     /*
    3759             :      * First, get the column's ACL from its pg_attribute entry
    3760             :      */
    3761        1242 :     attTuple = SearchSysCache2(ATTNUM,
    3762             :                                ObjectIdGetDatum(table_oid),
    3763             :                                Int16GetDatum(attnum));
    3764        1242 :     if (!HeapTupleIsValid(attTuple))
    3765           0 :         ereport(ERROR,
    3766             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    3767             :                  errmsg("attribute %d of relation with OID %u does not exist",
    3768             :                         attnum, table_oid)));
    3769        1242 :     attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
    3770             : 
    3771             :     /* Throw error on dropped columns, too */
    3772        1242 :     if (attributeForm->attisdropped)
    3773           0 :         ereport(ERROR,
    3774             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    3775             :                  errmsg("attribute %d of relation with OID %u does not exist",
    3776             :                         attnum, table_oid)));
    3777             : 
    3778        1242 :     aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
    3779             :                                &isNull);
    3780             : 
    3781             :     /*
    3782             :      * Here we hard-wire knowledge that the default ACL for a column grants no
    3783             :      * privileges, so that we can fall out quickly in the very common case
    3784             :      * where attacl is null.
    3785             :      */
    3786        1242 :     if (isNull)
    3787             :     {
    3788         330 :         ReleaseSysCache(attTuple);
    3789         330 :         return 0;
    3790             :     }
    3791             : 
    3792             :     /*
    3793             :      * Must get the relation's ownerId from pg_class.  Since we already found
    3794             :      * a pg_attribute entry, the only likely reason for this to fail is that a
    3795             :      * concurrent DROP of the relation committed since then (which could only
    3796             :      * happen if we don't have lock on the relation).  We prefer to report "no
    3797             :      * privileges" rather than failing in such a case, so as to avoid unwanted
    3798             :      * failures in has_column_privilege() tests.
    3799             :      */
    3800         912 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3801         912 :     if (!HeapTupleIsValid(classTuple))
    3802             :     {
    3803           0 :         ReleaseSysCache(attTuple);
    3804           0 :         return 0;
    3805             :     }
    3806         912 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3807             : 
    3808         912 :     ownerId = classForm->relowner;
    3809             : 
    3810         912 :     ReleaseSysCache(classTuple);
    3811             : 
    3812             :     /* detoast column's ACL if necessary */
    3813         912 :     acl = DatumGetAclP(aclDatum);
    3814             : 
    3815         912 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3816             : 
    3817             :     /* if we have a detoasted copy, free it */
    3818         912 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3819         912 :         pfree(acl);
    3820             : 
    3821         912 :     ReleaseSysCache(attTuple);
    3822             : 
    3823         912 :     return result;
    3824             : }
    3825             : 
    3826             : /*
    3827             :  * Exported routine for examining a user's privileges for a table
    3828             :  */
    3829             : AclMode
    3830     1014514 : pg_class_aclmask(Oid table_oid, Oid roleid,
    3831             :                  AclMode mask, AclMaskHow how)
    3832             : {
    3833             :     AclMode     result;
    3834             :     HeapTuple   tuple;
    3835             :     Form_pg_class classForm;
    3836             :     Datum       aclDatum;
    3837             :     bool        isNull;
    3838             :     Acl        *acl;
    3839             :     Oid         ownerId;
    3840             : 
    3841             :     /*
    3842             :      * Must get the relation's tuple from pg_class
    3843             :      */
    3844     1014514 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3845     1014514 :     if (!HeapTupleIsValid(tuple))
    3846           0 :         ereport(ERROR,
    3847             :                 (errcode(ERRCODE_UNDEFINED_TABLE),
    3848             :                  errmsg("relation with OID %u does not exist",
    3849             :                         table_oid)));
    3850     1014514 :     classForm = (Form_pg_class) GETSTRUCT(tuple);
    3851             : 
    3852             :     /*
    3853             :      * Deny anyone permission to update a system catalog unless
    3854             :      * pg_authid.rolsuper is set.  Also allow it if allowSystemTableMods.
    3855             :      *
    3856             :      * As of 7.4 we have some updatable system views; those shouldn't be
    3857             :      * protected in this way.  Assume the view rules can take care of
    3858             :      * themselves.  ACL_USAGE is if we ever have system sequences.
    3859             :      */
    3860     1241006 :     if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
    3861      241896 :         IsSystemClass(table_oid, classForm) &&
    3862       30808 :         classForm->relkind != RELKIND_VIEW &&
    3863       15436 :         !superuser_arg(roleid) &&
    3864          32 :         !allowSystemTableMods)
    3865             :     {
    3866             : #ifdef ACLDEBUG
    3867             :         elog(DEBUG2, "permission denied for system catalog update");
    3868             : #endif
    3869          32 :         mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
    3870             :     }
    3871             : 
    3872             :     /*
    3873             :      * Otherwise, superusers bypass all permission-checking.
    3874             :      */
    3875     1014514 :     if (superuser_arg(roleid))
    3876             :     {
    3877             : #ifdef ACLDEBUG
    3878             :         elog(DEBUG2, "OID %u is superuser, home free", roleid);
    3879             : #endif
    3880     1003252 :         ReleaseSysCache(tuple);
    3881     1003252 :         return mask;
    3882             :     }
    3883             : 
    3884             :     /*
    3885             :      * Normal case: get the relation's ACL from pg_class
    3886             :      */
    3887       11262 :     ownerId = classForm->relowner;
    3888             : 
    3889       11262 :     aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    3890             :                                &isNull);
    3891       11262 :     if (isNull)
    3892             :     {
    3893             :         /* No ACL, so build default ACL */
    3894        1636 :         switch (classForm->relkind)
    3895             :         {
    3896             :             case RELKIND_SEQUENCE:
    3897          24 :                 acl = acldefault(OBJECT_SEQUENCE, ownerId);
    3898          24 :                 break;
    3899             :             default:
    3900        1612 :                 acl = acldefault(OBJECT_TABLE, ownerId);
    3901        1612 :                 break;
    3902             :         }
    3903        1636 :         aclDatum = (Datum) 0;
    3904             :     }
    3905             :     else
    3906             :     {
    3907             :         /* detoast rel's ACL if necessary */
    3908        9626 :         acl = DatumGetAclP(aclDatum);
    3909             :     }
    3910             : 
    3911       11262 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3912             : 
    3913             :     /* if we have a detoasted copy, free it */
    3914       11262 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3915       11262 :         pfree(acl);
    3916             : 
    3917       11262 :     ReleaseSysCache(tuple);
    3918             : 
    3919       11262 :     return result;
    3920             : }
    3921             : 
    3922             : /*
    3923             :  * Exported routine for examining a user's privileges for a database
    3924             :  */
    3925             : AclMode
    3926        1624 : pg_database_aclmask(Oid db_oid, Oid roleid,
    3927             :                     AclMode mask, AclMaskHow how)
    3928             : {
    3929             :     AclMode     result;
    3930             :     HeapTuple   tuple;
    3931             :     Datum       aclDatum;
    3932             :     bool        isNull;
    3933             :     Acl        *acl;
    3934             :     Oid         ownerId;
    3935             : 
    3936             :     /* Superusers bypass all permission checking. */
    3937        1624 :     if (superuser_arg(roleid))
    3938        1362 :         return mask;
    3939             : 
    3940             :     /*
    3941             :      * Get the database's ACL from pg_database
    3942             :      */
    3943         262 :     tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
    3944         262 :     if (!HeapTupleIsValid(tuple))
    3945           0 :         ereport(ERROR,
    3946             :                 (errcode(ERRCODE_UNDEFINED_DATABASE),
    3947             :                  errmsg("database with OID %u does not exist", db_oid)));
    3948             : 
    3949         262 :     ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
    3950             : 
    3951         262 :     aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
    3952             :                                &isNull);
    3953         262 :     if (isNull)
    3954             :     {
    3955             :         /* No ACL, so build default ACL */
    3956         208 :         acl = acldefault(OBJECT_DATABASE, ownerId);
    3957         208 :         aclDatum = (Datum) 0;
    3958             :     }
    3959             :     else
    3960             :     {
    3961             :         /* detoast ACL if necessary */
    3962          54 :         acl = DatumGetAclP(aclDatum);
    3963             :     }
    3964             : 
    3965         262 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3966             : 
    3967             :     /* if we have a detoasted copy, free it */
    3968         262 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3969         262 :         pfree(acl);
    3970             : 
    3971         262 :     ReleaseSysCache(tuple);
    3972             : 
    3973         262 :     return result;
    3974             : }
    3975             : 
    3976             : /*
    3977             :  * Exported routine for examining a user's privileges for a function
    3978             :  */
    3979             : AclMode
    3980      931114 : pg_proc_aclmask(Oid proc_oid, Oid roleid,
    3981             :                 AclMode mask, AclMaskHow how)
    3982             : {
    3983             :     AclMode     result;
    3984             :     HeapTuple   tuple;
    3985             :     Datum       aclDatum;
    3986             :     bool        isNull;
    3987             :     Acl        *acl;
    3988             :     Oid         ownerId;
    3989             : 
    3990             :     /* Superusers bypass all permission checking. */
    3991      931114 :     if (superuser_arg(roleid))
    3992      917882 :         return mask;
    3993             : 
    3994             :     /*
    3995             :      * Get the function's ACL from pg_proc
    3996             :      */
    3997       13232 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
    3998       13232 :     if (!HeapTupleIsValid(tuple))
    3999           0 :         ereport(ERROR,
    4000             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4001             :                  errmsg("function with OID %u does not exist", proc_oid)));
    4002             : 
    4003       13232 :     ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
    4004             : 
    4005       13232 :     aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
    4006             :                                &isNull);
    4007       13232 :     if (isNull)
    4008             :     {
    4009             :         /* No ACL, so build default ACL */
    4010       12206 :         acl = acldefault(OBJECT_FUNCTION, ownerId);
    4011       12206 :         aclDatum = (Datum) 0;
    4012             :     }
    4013             :     else
    4014             :     {
    4015             :         /* detoast ACL if necessary */
    4016        1026 :         acl = DatumGetAclP(aclDatum);
    4017             :     }
    4018             : 
    4019       13232 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4020             : 
    4021             :     /* if we have a detoasted copy, free it */
    4022       13232 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4023       13232 :         pfree(acl);
    4024             : 
    4025       13232 :     ReleaseSysCache(tuple);
    4026             : 
    4027       13232 :     return result;
    4028             : }
    4029             : 
    4030             : /*
    4031             :  * Exported routine for examining a user's privileges for a language
    4032             :  */
    4033             : AclMode
    4034       30998 : pg_language_aclmask(Oid lang_oid, Oid roleid,
    4035             :                     AclMode mask, AclMaskHow how)
    4036             : {
    4037             :     AclMode     result;
    4038             :     HeapTuple   tuple;
    4039             :     Datum       aclDatum;
    4040             :     bool        isNull;
    4041             :     Acl        *acl;
    4042             :     Oid         ownerId;
    4043             : 
    4044             :     /* Superusers bypass all permission checking. */
    4045       30998 :     if (superuser_arg(roleid))
    4046       30786 :         return mask;
    4047             : 
    4048             :     /*
    4049             :      * Get the language's ACL from pg_language
    4050             :      */
    4051         212 :     tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
    4052         212 :     if (!HeapTupleIsValid(tuple))
    4053           0 :         ereport(ERROR,
    4054             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4055             :                  errmsg("language with OID %u does not exist", lang_oid)));
    4056             : 
    4057         212 :     ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
    4058             : 
    4059         212 :     aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
    4060             :                                &isNull);
    4061         212 :     if (isNull)
    4062             :     {
    4063             :         /* No ACL, so build default ACL */
    4064          52 :         acl = acldefault(OBJECT_LANGUAGE, ownerId);
    4065          52 :         aclDatum = (Datum) 0;
    4066             :     }
    4067             :     else
    4068             :     {
    4069             :         /* detoast ACL if necessary */
    4070         160 :         acl = DatumGetAclP(aclDatum);
    4071             :     }
    4072             : 
    4073         212 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4074             : 
    4075             :     /* if we have a detoasted copy, free it */
    4076         212 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4077         212 :         pfree(acl);
    4078             : 
    4079         212 :     ReleaseSysCache(tuple);
    4080             : 
    4081         212 :     return result;
    4082             : }
    4083             : 
    4084             : /*
    4085             :  * Exported routine for examining a user's privileges for a largeobject
    4086             :  *
    4087             :  * When a large object is opened for reading, it is opened relative to the
    4088             :  * caller's snapshot, but when it is opened for writing, a current
    4089             :  * MVCC snapshot will be used.  See doc/src/sgml/lobj.sgml.  This function
    4090             :  * takes a snapshot argument so that the permissions check can be made
    4091             :  * relative to the same snapshot that will be used to read the underlying
    4092             :  * data.  The caller will actually pass NULL for an instantaneous MVCC
    4093             :  * snapshot, since all we do with the snapshot argument is pass it through
    4094             :  * to systable_beginscan().
    4095             :  */
    4096             : AclMode
    4097         324 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
    4098             :                                 AclMode mask, AclMaskHow how,
    4099             :                                 Snapshot snapshot)
    4100             : {
    4101             :     AclMode     result;
    4102             :     Relation    pg_lo_meta;
    4103             :     ScanKeyData entry[1];
    4104             :     SysScanDesc scan;
    4105             :     HeapTuple   tuple;
    4106             :     Datum       aclDatum;
    4107             :     bool        isNull;
    4108             :     Acl        *acl;
    4109             :     Oid         ownerId;
    4110             : 
    4111             :     /* Superusers bypass all permission checking. */
    4112         324 :     if (superuser_arg(roleid))
    4113         224 :         return mask;
    4114             : 
    4115             :     /*
    4116             :      * Get the largeobject's ACL from pg_largeobject_metadata
    4117             :      */
    4118         100 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
    4119             :                             AccessShareLock);
    4120             : 
    4121         100 :     ScanKeyInit(&entry[0],
    4122             :                 Anum_pg_largeobject_metadata_oid,
    4123             :                 BTEqualStrategyNumber, F_OIDEQ,
    4124             :                 ObjectIdGetDatum(lobj_oid));
    4125             : 
    4126         100 :     scan = systable_beginscan(pg_lo_meta,
    4127             :                               LargeObjectMetadataOidIndexId, true,
    4128             :                               snapshot, 1, entry);
    4129             : 
    4130         100 :     tuple = systable_getnext(scan);
    4131         100 :     if (!HeapTupleIsValid(tuple))
    4132           0 :         ereport(ERROR,
    4133             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4134             :                  errmsg("large object %u does not exist", lobj_oid)));
    4135             : 
    4136         100 :     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
    4137             : 
    4138         100 :     aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
    4139             :                             RelationGetDescr(pg_lo_meta), &isNull);
    4140             : 
    4141         100 :     if (isNull)
    4142             :     {
    4143             :         /* No ACL, so build default ACL */
    4144          24 :         acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    4145          24 :         aclDatum = (Datum) 0;
    4146             :     }
    4147             :     else
    4148             :     {
    4149             :         /* detoast ACL if necessary */
    4150          76 :         acl = DatumGetAclP(aclDatum);
    4151             :     }
    4152             : 
    4153         100 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4154             : 
    4155             :     /* if we have a detoasted copy, free it */
    4156         100 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4157         100 :         pfree(acl);
    4158             : 
    4159         100 :     systable_endscan(scan);
    4160             : 
    4161         100 :     table_close(pg_lo_meta, AccessShareLock);
    4162             : 
    4163         100 :     return result;
    4164             : }
    4165             : 
    4166             : /*
    4167             :  * Exported routine for examining a user's privileges for a namespace
    4168             :  */
    4169             : AclMode
    4170      692056 : pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
    4171             :                      AclMode mask, AclMaskHow how)
    4172             : {
    4173             :     AclMode     result;
    4174             :     HeapTuple   tuple;
    4175             :     Datum       aclDatum;
    4176             :     bool        isNull;
    4177             :     Acl        *acl;
    4178             :     Oid         ownerId;
    4179             : 
    4180             :     /* Superusers bypass all permission checking. */
    4181      692056 :     if (superuser_arg(roleid))
    4182      684002 :         return mask;
    4183             : 
    4184             :     /*
    4185             :      * If we have been assigned this namespace as a temp namespace, check to
    4186             :      * make sure we have CREATE TEMP permission on the database, and if so act
    4187             :      * as though we have all standard (but not GRANT OPTION) permissions on
    4188             :      * the namespace.  If we don't have CREATE TEMP, act as though we have
    4189             :      * only USAGE (and not CREATE) rights.
    4190             :      *
    4191             :      * This may seem redundant given the check in InitTempTableNamespace, but
    4192             :      * it really isn't since current user ID may have changed since then. The
    4193             :      * upshot of this behavior is that a SECURITY DEFINER function can create
    4194             :      * temp tables that can then be accessed (if permission is granted) by
    4195             :      * code in the same session that doesn't have permissions to create temp
    4196             :      * tables.
    4197             :      *
    4198             :      * XXX Would it be safe to ereport a special error message as
    4199             :      * InitTempTableNamespace does?  Returning zero here means we'll get a
    4200             :      * generic "permission denied for schema pg_temp_N" message, which is not
    4201             :      * remarkably user-friendly.
    4202             :      */
    4203        8054 :     if (isTempNamespace(nsp_oid))
    4204             :     {
    4205          82 :         if (pg_database_aclcheck(MyDatabaseId, roleid,
    4206             :                                  ACL_CREATE_TEMP) == ACLCHECK_OK)
    4207          82 :             return mask & ACL_ALL_RIGHTS_SCHEMA;
    4208             :         else
    4209           0 :             return mask & ACL_USAGE;
    4210             :     }
    4211             : 
    4212             :     /*
    4213             :      * Get the schema's ACL from pg_namespace
    4214             :      */
    4215        7972 :     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
    4216        7972 :     if (!HeapTupleIsValid(tuple))
    4217           0 :         ereport(ERROR,
    4218             :                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
    4219             :                  errmsg("schema with OID %u does not exist", nsp_oid)));
    4220             : 
    4221        7972 :     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
    4222             : 
    4223        7972 :     aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
    4224             :                                &isNull);
    4225        7972 :     if (isNull)
    4226             :     {
    4227             :         /* No ACL, so build default ACL */
    4228         130 :         acl = acldefault(OBJECT_SCHEMA, ownerId);
    4229         130 :         aclDatum = (Datum) 0;
    4230             :     }
    4231             :     else
    4232             :     {
    4233             :         /* detoast ACL if necessary */
    4234        7842 :         acl = DatumGetAclP(aclDatum);
    4235             :     }
    4236             : 
    4237        7972 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4238             : 
    4239             :     /* if we have a detoasted copy, free it */
    4240        7972 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4241        7972 :         pfree(acl);
    4242             : 
    4243        7972 :     ReleaseSysCache(tuple);
    4244             : 
    4245        7972 :     return result;
    4246             : }
    4247             : 
    4248             : /*
    4249             :  * Exported routine for examining a user's privileges for a tablespace
    4250             :  */
    4251             : AclMode
    4252         174 : pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
    4253             :                       AclMode mask, AclMaskHow how)
    4254             : {
    4255             :     AclMode     result;
    4256             :     HeapTuple   tuple;
    4257             :     Datum       aclDatum;
    4258             :     bool        isNull;
    4259             :     Acl        *acl;
    4260             :     Oid         ownerId;
    4261             : 
    4262             :     /* Superusers bypass all permission checking. */
    4263         174 :     if (superuser_arg(roleid))
    4264         170 :         return mask;
    4265             : 
    4266             :     /*
    4267             :      * Get the tablespace's ACL from pg_tablespace
    4268             :      */
    4269           4 :     tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
    4270           4 :     if (!HeapTupleIsValid(tuple))
    4271           0 :         ereport(ERROR,
    4272             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4273             :                  errmsg("tablespace with OID %u does not exist", spc_oid)));
    4274             : 
    4275           4 :     ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
    4276             : 
    4277           4 :     aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
    4278             :                                Anum_pg_tablespace_spcacl,
    4279             :                                &isNull);
    4280             : 
    4281           4 :     if (isNull)
    4282             :     {
    4283             :         /* No ACL, so build default ACL */
    4284           4 :         acl = acldefault(OBJECT_TABLESPACE, ownerId);
    4285           4 :         aclDatum = (Datum) 0;
    4286             :     }
    4287             :     else
    4288             :     {
    4289             :         /* detoast ACL if necessary */
    4290           0 :         acl = DatumGetAclP(aclDatum);
    4291             :     }
    4292             : 
    4293           4 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4294             : 
    4295             :     /* if we have a detoasted copy, free it */
    4296           4 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4297           4 :         pfree(acl);
    4298             : 
    4299           4 :     ReleaseSysCache(tuple);
    4300             : 
    4301           4 :     return result;
    4302             : }
    4303             : 
    4304             : /*
    4305             :  * Exported routine for examining a user's privileges for a foreign
    4306             :  * data wrapper
    4307             :  */
    4308             : AclMode
    4309         198 : pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
    4310             :                                 AclMode mask, AclMaskHow how)
    4311             : {
    4312             :     AclMode     result;
    4313             :     HeapTuple   tuple;
    4314             :     Datum       aclDatum;
    4315             :     bool        isNull;
    4316             :     Acl        *acl;
    4317             :     Oid         ownerId;
    4318             : 
    4319             :     Form_pg_foreign_data_wrapper fdwForm;
    4320             : 
    4321             :     /* Bypass permission checks for superusers */
    4322         198 :     if (superuser_arg(roleid))
    4323         124 :         return mask;
    4324             : 
    4325             :     /*
    4326             :      * Must get the FDW's tuple from pg_foreign_data_wrapper
    4327             :      */
    4328          74 :     tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
    4329          74 :     if (!HeapTupleIsValid(tuple))
    4330           0 :         ereport(ERROR,
    4331             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4332             :                  errmsg("foreign-data wrapper with OID %u does not exist",
    4333             :                         fdw_oid)));
    4334          74 :     fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
    4335             : 
    4336             :     /*
    4337             :      * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
    4338             :      */
    4339          74 :     ownerId = fdwForm->fdwowner;
    4340             : 
    4341          74 :     aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
    4342             :                                Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
    4343          74 :     if (isNull)
    4344             :     {
    4345             :         /* No ACL, so build default ACL */
    4346           6 :         acl = acldefault(OBJECT_FDW, ownerId);
    4347           6 :         aclDatum = (Datum) 0;
    4348             :     }
    4349             :     else
    4350             :     {
    4351             :         /* detoast rel's ACL if necessary */
    4352          68 :         acl = DatumGetAclP(aclDatum);
    4353             :     }
    4354             : 
    4355          74 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4356             : 
    4357             :     /* if we have a detoasted copy, free it */
    4358          74 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4359          74 :         pfree(acl);
    4360             : 
    4361          74 :     ReleaseSysCache(tuple);
    4362             : 
    4363          74 :     return result;
    4364             : }
    4365             : 
    4366             : /*
    4367             :  * Exported routine for examining a user's privileges for a foreign
    4368             :  * server.
    4369             :  */
    4370             : AclMode
    4371         392 : pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
    4372             :                           AclMode mask, AclMaskHow how)
    4373             : {
    4374             :     AclMode     result;
    4375             :     HeapTuple   tuple;
    4376             :     Datum       aclDatum;
    4377             :     bool        isNull;
    4378             :     Acl        *acl;
    4379             :     Oid         ownerId;
    4380             : 
    4381             :     Form_pg_foreign_server srvForm;
    4382             : 
    4383             :     /* Bypass permission checks for superusers */
    4384         392 :     if (superuser_arg(roleid))
    4385         296 :         return mask;
    4386             : 
    4387             :     /*
    4388             :      * Must get the FDW's tuple from pg_foreign_data_wrapper
    4389             :      */
    4390          96 :     tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
    4391          96 :     if (!HeapTupleIsValid(tuple))
    4392           0 :         ereport(ERROR,
    4393             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4394             :                  errmsg("foreign server with OID %u does not exist",
    4395             :                         srv_oid)));
    4396          96 :     srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
    4397             : 
    4398             :     /*
    4399             :      * Normal case: get the foreign server's ACL from pg_foreign_server
    4400             :      */
    4401          96 :     ownerId = srvForm->srvowner;
    4402             : 
    4403          96 :     aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
    4404             :                                Anum_pg_foreign_server_srvacl, &isNull);
    4405          96 :     if (isNull)
    4406             :     {
    4407             :         /* No ACL, so build default ACL */
    4408          62 :         acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
    4409          62 :         aclDatum = (Datum) 0;
    4410             :     }
    4411             :     else
    4412             :     {
    4413             :         /* detoast rel's ACL if necessary */
    4414          34 :         acl = DatumGetAclP(aclDatum);
    4415             :     }
    4416             : 
    4417          96 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4418             : 
    4419             :     /* if we have a detoasted copy, free it */
    4420          96 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4421          96 :         pfree(acl);
    4422             : 
    4423          96 :     ReleaseSysCache(tuple);
    4424             : 
    4425          96 :     return result;
    4426             : }
    4427             : 
    4428             : /*
    4429             :  * Exported routine for examining a user's privileges for a type.
    4430             :  */
    4431             : AclMode
    4432      554226 : pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
    4433             : {
    4434             :     AclMode     result;
    4435             :     HeapTuple   tuple;
    4436             :     Datum       aclDatum;
    4437             :     bool        isNull;
    4438             :     Acl        *acl;
    4439             :     Oid         ownerId;
    4440             : 
    4441             :     Form_pg_type typeForm;
    4442             : 
    4443             :     /* Bypass permission checks for superusers */
    4444      554226 :     if (superuser_arg(roleid))
    4445      552182 :         return mask;
    4446             : 
    4447             :     /*
    4448             :      * Must get the type's tuple from pg_type
    4449             :      */
    4450        2044 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
    4451        2044 :     if (!HeapTupleIsValid(tuple))
    4452           0 :         ereport(ERROR,
    4453             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4454             :                  errmsg("type with OID %u does not exist",
    4455             :                         type_oid)));
    4456        2044 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
    4457             : 
    4458             :     /*
    4459             :      * "True" array types don't manage permissions of their own; consult the
    4460             :      * element type instead.
    4461             :      */
    4462        2044 :     if (OidIsValid(typeForm->typelem) && typeForm->typlen == -1)
    4463             :     {
    4464          40 :         Oid         elttype_oid = typeForm->typelem;
    4465             : 
    4466          40 :         ReleaseSysCache(tuple);
    4467             : 
    4468          40 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
    4469             :         /* this case is not a user-facing error, so elog not ereport */
    4470          40 :         if (!HeapTupleIsValid(tuple))
    4471           0 :             elog(ERROR, "cache lookup failed for type %u", elttype_oid);
    4472          40 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    4473             :     }
    4474             : 
    4475             :     /*
    4476             :      * Now get the type's owner and ACL from the tuple
    4477             :      */
    4478        2044 :     ownerId = typeForm->typowner;
    4479             : 
    4480        2044 :     aclDatum = SysCacheGetAttr(TYPEOID, tuple,
    4481             :                                Anum_pg_type_typacl, &isNull);
    4482        2044 :     if (isNull)
    4483             :     {
    4484             :         /* No ACL, so build default ACL */
    4485        1896 :         acl = acldefault(OBJECT_TYPE, ownerId);
    4486        1896 :         aclDatum = (Datum) 0;
    4487             :     }
    4488             :     else
    4489             :     {
    4490             :         /* detoast rel's ACL if necessary */
    4491         148 :         acl = DatumGetAclP(aclDatum);
    4492             :     }
    4493             : 
    4494        2044 :     result = aclmask(acl, roleid, ownerId, mask, how);
    4495             : 
    4496             :     /* if we have a detoasted copy, free it */
    4497        2044 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    4498        2044 :         pfree(acl);
    4499             : 
    4500        2044 :     ReleaseSysCache(tuple);
    4501             : 
    4502        2044 :     return result;
    4503             : }
    4504             : 
    4505             : /*
    4506             :  * Exported routine for checking a user's access privileges to a column
    4507             :  *
    4508             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    4509             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    4510             :  * ACLCHECK_NO_PRIV).
    4511             :  *
    4512             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    4513             :  * column are considered here.
    4514             :  */
    4515             : AclResult
    4516        1166 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
    4517             :                       Oid roleid, AclMode mode)
    4518             : {
    4519        1166 :     if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
    4520         668 :         return ACLCHECK_OK;
    4521             :     else
    4522         498 :         return ACLCHECK_NO_PRIV;
    4523             : }
    4524             : 
    4525             : /*
    4526             :  * Exported routine for checking a user's access privileges to any/all columns
    4527             :  *
    4528             :  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
    4529             :  * privileges identified by 'mode' on any non-dropped column in the relation;
    4530             :  * otherwise returns a suitable error code (in practice, always
    4531             :  * ACLCHECK_NO_PRIV).
    4532             :  *
    4533             :  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
    4534             :  * privileges identified by 'mode' on each non-dropped column in the relation
    4535             :  * (and there must be at least one such column); otherwise returns a suitable
    4536             :  * error code (in practice, always ACLCHECK_NO_PRIV).
    4537             :  *
    4538             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    4539             :  * column(s) are considered here.
    4540             :  *
    4541             :  * Note: system columns are not considered here; there are cases where that
    4542             :  * might be appropriate but there are also cases where it wouldn't.
    4543             :  */
    4544             : AclResult
    4545          68 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
    4546             :                           AclMaskHow how)
    4547             : {
    4548             :     AclResult   result;
    4549             :     HeapTuple   classTuple;
    4550             :     Form_pg_class classForm;
    4551             :     AttrNumber  nattrs;
    4552             :     AttrNumber  curr_att;
    4553             : 
    4554             :     /*
    4555             :      * Must fetch pg_class row to check number of attributes.  As in
    4556             :      * pg_attribute_aclmask, we prefer to return "no privileges" instead of
    4557             :      * throwing an error if we get any unexpected lookup errors.
    4558             :      */
    4559          68 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    4560          68 :     if (!HeapTupleIsValid(classTuple))
    4561           0 :         return ACLCHECK_NO_PRIV;
    4562          68 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    4563             : 
    4564          68 :     nattrs = classForm->relnatts;
    4565             : 
    4566          68 :     ReleaseSysCache(classTuple);
    4567             : 
    4568             :     /*
    4569             :      * Initialize result in case there are no non-dropped columns.  We want to
    4570             :      * report failure in such cases for either value of 'how'.
    4571             :      */
    4572          68 :     result = ACLCHECK_NO_PRIV;
    4573             : 
    4574         224 :     for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4575             :     {
    4576             :         HeapTuple   attTuple;
    4577             :         AclMode     attmask;
    4578             : 
    4579         176 :         attTuple = SearchSysCache2(ATTNUM,
    4580             :                                    ObjectIdGetDatum(table_oid),
    4581             :                                    Int16GetDatum(curr_att));
    4582         176 :         if (!HeapTupleIsValid(attTuple))
    4583           0 :             continue;
    4584             : 
    4585             :         /* ignore dropped columns */
    4586         176 :         if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    4587             :         {
    4588          12 :             ReleaseSysCache(attTuple);
    4589          12 :             continue;
    4590             :         }
    4591             : 
    4592             :         /*
    4593             :          * Here we hard-wire knowledge that the default ACL for a column
    4594             :          * grants no privileges, so that we can fall out quickly in the very
    4595             :          * common case where attacl is null.
    4596             :          */
    4597         164 :         if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
    4598          88 :             attmask = 0;
    4599             :         else
    4600          76 :             attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
    4601             :                                            mode, ACLMASK_ANY);
    4602             : 
    4603         164 :         ReleaseSysCache(attTuple);
    4604             : 
    4605         164 :         if (attmask != 0)
    4606             :         {
    4607          68 :             result = ACLCHECK_OK;
    4608          68 :             if (how == ACLMASK_ANY)
    4609           8 :                 break;          /* succeed on any success */
    4610             :         }
    4611             :         else
    4612             :         {
    4613          96 :             result = ACLCHECK_NO_PRIV;
    4614          96 :             if (how == ACLMASK_ALL)
    4615          12 :                 break;          /* fail on any failure */
    4616             :         }
    4617             :     }
    4618             : 
    4619          68 :     return result;
    4620             : }
    4621             : 
    4622             : /*
    4623             :  * Exported routine for checking a user's access privileges to a table
    4624             :  *
    4625             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    4626             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    4627             :  * ACLCHECK_NO_PRIV).
    4628             :  */
    4629             : AclResult
    4630      697140 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
    4631             : {
    4632      697140 :     if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
    4633      696756 :         return ACLCHECK_OK;
    4634             :     else
    4635         384 :         return ACLCHECK_NO_PRIV;
    4636             : }
    4637             : 
    4638             : /*
    4639             :  * Exported routine for checking a user's access privileges to a database
    4640             :  */
    4641             : AclResult
    4642        1624 : pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
    4643             : {
    4644        1624 :     if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
    4645        1620 :         return ACLCHECK_OK;
    4646             :     else
    4647           4 :         return ACLCHECK_NO_PRIV;
    4648             : }
    4649             : 
    4650             : /*
    4651             :  * Exported routine for checking a user's access privileges to a function
    4652             :  */
    4653             : AclResult
    4654      931114 : pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
    4655             : {
    4656      931114 :     if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
    4657      931030 :         return ACLCHECK_OK;
    4658             :     else
    4659          84 :         return ACLCHECK_NO_PRIV;
    4660             : }
    4661             : 
    4662             : /*
    4663             :  * Exported routine for checking a user's access privileges to a language
    4664             :  */
    4665             : AclResult
    4666       30994 : pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
    4667             : {
    4668       30994 :     if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
    4669       30990 :         return ACLCHECK_OK;
    4670             :     else
    4671           4 :         return ACLCHECK_NO_PRIV;
    4672             : }
    4673             : 
    4674             : /*
    4675             :  * Exported routine for checking a user's access privileges to a largeobject
    4676             :  */
    4677             : AclResult
    4678         324 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
    4679             :                                  Snapshot snapshot)
    4680             : {
    4681         324 :     if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
    4682             :                                         ACLMASK_ANY, snapshot) != 0)
    4683         288 :         return ACLCHECK_OK;
    4684             :     else
    4685          36 :         return ACLCHECK_NO_PRIV;
    4686             : }
    4687             : 
    4688             : /*
    4689             :  * Exported routine for checking a user's access privileges to a namespace
    4690             :  */
    4691             : AclResult
    4692      692056 : pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
    4693             : {
    4694      692056 :     if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
    4695      692026 :         return ACLCHECK_OK;
    4696             :     else
    4697          30 :         return ACLCHECK_NO_PRIV;
    4698             : }
    4699             : 
    4700             : /*
    4701             :  * Exported routine for checking a user's access privileges to a tablespace
    4702             :  */
    4703             : AclResult
    4704         174 : pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
    4705             : {
    4706         174 :     if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
    4707         170 :         return ACLCHECK_OK;
    4708             :     else
    4709           4 :         return ACLCHECK_NO_PRIV;
    4710             : }
    4711             : 
    4712             : /*
    4713             :  * Exported routine for checking a user's access privileges to a foreign
    4714             :  * data wrapper
    4715             :  */
    4716             : AclResult
    4717         186 : pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
    4718             : {
    4719         186 :     if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
    4720         164 :         return ACLCHECK_OK;
    4721             :     else
    4722          22 :         return ACLCHECK_NO_PRIV;
    4723             : }
    4724             : 
    4725             : /*
    4726             :  * Exported routine for checking a user's access privileges to a foreign
    4727             :  * server
    4728             :  */
    4729             : AclResult
    4730         380 : pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
    4731             : {
    4732         380 :     if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
    4733         318 :         return ACLCHECK_OK;
    4734             :     else
    4735          62 :         return ACLCHECK_NO_PRIV;
    4736             : }
    4737             : 
    4738             : /*
    4739             :  * Exported routine for checking a user's access privileges to a type
    4740             :  */
    4741             : AclResult
    4742      554218 : pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
    4743             : {
    4744      554218 :     if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
    4745      554142 :         return ACLCHECK_OK;
    4746             :     else
    4747          76 :         return ACLCHECK_NO_PRIV;
    4748             : }
    4749             : 
    4750             : /*
    4751             :  * Ownership check for a relation (specified by OID).
    4752             :  */
    4753             : bool
    4754      430892 : pg_class_ownercheck(Oid class_oid, Oid roleid)
    4755             : {
    4756             :     HeapTuple   tuple;
    4757             :     Oid         ownerId;
    4758             : 
    4759             :     /* Superusers bypass all permission checking. */
    4760      430892 :     if (superuser_arg(roleid))
    4761      427512 :         return true;
    4762             : 
    4763        3380 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
    4764        3380 :     if (!HeapTupleIsValid(tuple))
    4765           0 :         ereport(ERROR,
    4766             :                 (errcode(ERRCODE_UNDEFINED_TABLE),
    4767             :                  errmsg("relation with OID %u does not exist", class_oid)));
    4768             : 
    4769        3380 :     ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
    4770             : 
    4771        3380 :     ReleaseSysCache(tuple);
    4772             : 
    4773        3380 :     return has_privs_of_role(roleid, ownerId);
    4774             : }
    4775             : 
    4776             : /*
    4777             :  * Ownership check for a type (specified by OID).
    4778             :  */
    4779             : bool
    4780         858 : pg_type_ownercheck(Oid type_oid, Oid roleid)
    4781             : {
    4782             :     HeapTuple   tuple;
    4783             :     Oid         ownerId;
    4784             : 
    4785             :     /* Superusers bypass all permission checking. */
    4786         858 :     if (superuser_arg(roleid))
    4787         818 :         return true;
    4788             : 
    4789          40 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
    4790          40 :     if (!HeapTupleIsValid(tuple))
    4791           0 :         ereport(ERROR,
    4792             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4793             :                  errmsg("type with OID %u does not exist", type_oid)));
    4794             : 
    4795          40 :     ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
    4796             : 
    4797          40 :     ReleaseSysCache(tuple);
    4798             : 
    4799          40 :     return has_privs_of_role(roleid, ownerId);
    4800             : }
    4801             : 
    4802             : /*
    4803             :  * Ownership check for an operator (specified by OID).
    4804             :  */
    4805             : bool
    4806        2000 : pg_oper_ownercheck(Oid oper_oid, Oid roleid)
    4807             : {
    4808             :     HeapTuple   tuple;
    4809             :     Oid         ownerId;
    4810             : 
    4811             :     /* Superusers bypass all permission checking. */
    4812        2000 :     if (superuser_arg(roleid))
    4813        1988 :         return true;
    4814             : 
    4815          12 :     tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
    4816          12 :     if (!HeapTupleIsValid(tuple))
    4817           0 :         ereport(ERROR,
    4818             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4819             :                  errmsg("operator with OID %u does not exist", oper_oid)));
    4820             : 
    4821          12 :     ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
    4822             : 
    4823          12 :     ReleaseSysCache(tuple);
    4824             : 
    4825          12 :     return has_privs_of_role(roleid, ownerId);
    4826             : }
    4827             : 
    4828             : /*
    4829             :  * Ownership check for a function (specified by OID).
    4830             :  */
    4831             : bool
    4832        9602 : pg_proc_ownercheck(Oid proc_oid, Oid roleid)
    4833             : {
    4834             :     HeapTuple   tuple;
    4835             :     Oid         ownerId;
    4836             : 
    4837             :     /* Superusers bypass all permission checking. */
    4838        9602 :     if (superuser_arg(roleid))
    4839        9534 :         return true;
    4840             : 
    4841          68 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
    4842          68 :     if (!HeapTupleIsValid(tuple))
    4843           0 :         ereport(ERROR,
    4844             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4845             :                  errmsg("function with OID %u does not exist", proc_oid)));
    4846             : 
    4847          68 :     ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
    4848             : 
    4849          68 :     ReleaseSysCache(tuple);
    4850             : 
    4851          68 :     return has_privs_of_role(roleid, ownerId);
    4852             : }
    4853             : 
    4854             : /*
    4855             :  * Ownership check for a procedural language (specified by OID)
    4856             :  */
    4857             : bool
    4858         362 : pg_language_ownercheck(Oid lan_oid, Oid roleid)
    4859             : {
    4860             :     HeapTuple   tuple;
    4861             :     Oid         ownerId;
    4862             : 
    4863             :     /* Superusers bypass all permission checking. */
    4864         362 :     if (superuser_arg(roleid))
    4865         362 :         return true;
    4866             : 
    4867           0 :     tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
    4868           0 :     if (!HeapTupleIsValid(tuple))
    4869           0 :         ereport(ERROR,
    4870             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4871             :                  errmsg("language with OID %u does not exist", lan_oid)));
    4872             : 
    4873           0 :     ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
    4874             : 
    4875           0 :     ReleaseSysCache(tuple);
    4876             : 
    4877           0 :     return has_privs_of_role(roleid, ownerId);
    4878             : }
    4879             : 
    4880             : /*
    4881             :  * Ownership check for a largeobject (specified by OID)
    4882             :  *
    4883             :  * This is only used for operations like ALTER LARGE OBJECT that are always
    4884             :  * relative to an up-to-date snapshot.
    4885             :  */
    4886             : bool
    4887          70 : pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
    4888             : {
    4889             :     Relation    pg_lo_meta;
    4890             :     ScanKeyData entry[1];
    4891             :     SysScanDesc scan;
    4892             :     HeapTuple   tuple;
    4893             :     Oid         ownerId;
    4894             : 
    4895             :     /* Superusers bypass all permission checking. */
    4896          70 :     if (superuser_arg(roleid))
    4897          58 :         return true;
    4898             : 
    4899             :     /* There's no syscache for pg_largeobject_metadata */
    4900          12 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
    4901             :                             AccessShareLock);
    4902             : 
    4903          12 :     ScanKeyInit(&entry[0],
    4904             :                 Anum_pg_largeobject_metadata_oid,
    4905             :                 BTEqualStrategyNumber, F_OIDEQ,
    4906             :                 ObjectIdGetDatum(lobj_oid));
    4907             : 
    4908          12 :     scan = systable_beginscan(pg_lo_meta,
    4909             :                               LargeObjectMetadataOidIndexId, true,
    4910             :                               NULL, 1, entry);
    4911             : 
    4912          12 :     tuple = systable_getnext(scan);
    4913          12 :     if (!HeapTupleIsValid(tuple))
    4914           0 :         ereport(ERROR,
    4915             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4916             :                  errmsg("large object %u does not exist", lobj_oid)));
    4917             : 
    4918          12 :     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
    4919             : 
    4920          12 :     systable_endscan(scan);
    4921          12 :     table_close(pg_lo_meta, AccessShareLock);
    4922             : 
    4923          12 :     return has_privs_of_role(roleid, ownerId);
    4924             : }
    4925             : 
    4926             : /*
    4927             :  * Ownership check for a namespace (specified by OID).
    4928             :  */
    4929             : bool
    4930        2800 : pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
    4931             : {
    4932             :     HeapTuple   tuple;
    4933             :     Oid         ownerId;
    4934             : 
    4935             :     /* Superusers bypass all permission checking. */
    4936        2800 :     if (superuser_arg(roleid))
    4937        2704 :         return true;
    4938             : 
    4939          96 :     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
    4940          96 :     if (!HeapTupleIsValid(tuple))
    4941           0 :         ereport(ERROR,
    4942             :                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
    4943             :                  errmsg("schema with OID %u does not exist", nsp_oid)));
    4944             : 
    4945          96 :     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
    4946             : 
    4947          96 :     ReleaseSysCache(tuple);
    4948             : 
    4949          96 :     return has_privs_of_role(roleid, ownerId);
    4950             : }
    4951             : 
    4952             : /*
    4953             :  * Ownership check for a tablespace (specified by OID).
    4954             :  */
    4955             : bool
    4956          40 : pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
    4957             : {
    4958             :     HeapTuple   spctuple;
    4959             :     Oid         spcowner;
    4960             : 
    4961             :     /* Superusers bypass all permission checking. */
    4962          40 :     if (superuser_arg(roleid))
    4963          40 :         return true;
    4964             : 
    4965             :     /* Search syscache for pg_tablespace */
    4966           0 :     spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
    4967           0 :     if (!HeapTupleIsValid(spctuple))
    4968           0 :         ereport(ERROR,
    4969             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4970             :                  errmsg("tablespace with OID %u does not exist", spc_oid)));
    4971             : 
    4972           0 :     spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
    4973             : 
    4974           0 :     ReleaseSysCache(spctuple);
    4975             : 
    4976           0 :     return has_privs_of_role(roleid, spcowner);
    4977             : }
    4978             : 
    4979             : /*
    4980             :  * Ownership check for an operator class (specified by OID).
    4981             :  */
    4982             : bool
    4983           4 : pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
    4984             : {
    4985             :     HeapTuple   tuple;
    4986             :     Oid         ownerId;
    4987             : 
    4988             :     /* Superusers bypass all permission checking. */
    4989           4 :     if (superuser_arg(roleid))
    4990           4 :         return true;
    4991             : 
    4992           0 :     tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
    4993           0 :     if (!HeapTupleIsValid(tuple))
    4994           0 :         ereport(ERROR,
    4995             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4996             :                  errmsg("operator class with OID %u does not exist",
    4997             :                         opc_oid)));
    4998             : 
    4999           0 :     ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
    5000             : 
    5001           0 :     ReleaseSysCache(tuple);
    5002             : 
    5003           0 :     return has_privs_of_role(roleid, ownerId);
    5004             : }
    5005             : 
    5006             : /*
    5007             :  * Ownership check for an operator family (specified by OID).
    5008             :  */
    5009             : bool
    5010           4 : pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
    5011             : {
    5012             :     HeapTuple   tuple;
    5013             :     Oid         ownerId;
    5014             : 
    5015             :     /* Superusers bypass all permission checking. */
    5016           4 :     if (superuser_arg(roleid))
    5017           4 :         return true;
    5018             : 
    5019           0 :     tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
    5020           0 :     if (!HeapTupleIsValid(tuple))
    5021           0 :         ereport(ERROR,
    5022             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5023             :                  errmsg("operator family with OID %u does not exist",
    5024             :                         opf_oid)));
    5025             : 
    5026           0 :     ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
    5027             : 
    5028           0 :     ReleaseSysCache(tuple);
    5029             : 
    5030           0 :     return has_privs_of_role(roleid, ownerId);
    5031             : }
    5032             : 
    5033             : /*
    5034             :  * Ownership check for a text search dictionary (specified by OID).
    5035             :  */
    5036             : bool
    5037        7104 : pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
    5038             : {
    5039             :     HeapTuple   tuple;
    5040             :     Oid         ownerId;
    5041             : 
    5042             :     /* Superusers bypass all permission checking. */
    5043        7104 :     if (superuser_arg(roleid))
    5044        7104 :         return true;
    5045             : 
    5046           0 :     tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
    5047           0 :     if (!HeapTupleIsValid(tuple))
    5048           0 :         ereport(ERROR,
    5049             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5050             :                  errmsg("text search dictionary with OID %u does not exist",
    5051             :                         dict_oid)));
    5052             : 
    5053           0 :     ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
    5054             : 
    5055           0 :     ReleaseSysCache(tuple);
    5056             : 
    5057           0 :     return has_privs_of_role(roleid, ownerId);
    5058             : }
    5059             : 
    5060             : /*
    5061             :  * Ownership check for a text search configuration (specified by OID).
    5062             :  */
    5063             : bool
    5064       28518 : pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
    5065             : {
    5066             :     HeapTuple   tuple;
    5067             :     Oid         ownerId;
    5068             : 
    5069             :     /* Superusers bypass all permission checking. */
    5070       28518 :     if (superuser_arg(roleid))
    5071       28518 :         return true;
    5072             : 
    5073           0 :     tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
    5074           0 :     if (!HeapTupleIsValid(tuple))
    5075           0 :         ereport(ERROR,
    5076             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5077             :                  errmsg("text search configuration with OID %u does not exist",
    5078             :                         cfg_oid)));
    5079             : 
    5080           0 :     ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
    5081             : 
    5082           0 :     ReleaseSysCache(tuple);
    5083             : 
    5084           0 :     return has_privs_of_role(roleid, ownerId);
    5085             : }
    5086             : 
    5087             : /*
    5088             :  * Ownership check for a foreign-data wrapper (specified by OID).
    5089             :  */
    5090             : bool
    5091          80 : pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
    5092             : {
    5093             :     HeapTuple   tuple;
    5094             :     Oid         ownerId;
    5095             : 
    5096             :     /* Superusers bypass all permission checking. */
    5097          80 :     if (superuser_arg(roleid))
    5098          64 :         return true;
    5099             : 
    5100          16 :     tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
    5101          16 :     if (!HeapTupleIsValid(tuple))
    5102           0 :         ereport(ERROR,
    5103             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5104             :                  errmsg("foreign-data wrapper with OID %u does not exist",
    5105             :                         srv_oid)));
    5106             : 
    5107          16 :     ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
    5108             : 
    5109          16 :     ReleaseSysCache(tuple);
    5110             : 
    5111          16 :     return has_privs_of_role(roleid, ownerId);
    5112             : }
    5113             : 
    5114             : /*
    5115             :  * Ownership check for a foreign server (specified by OID).
    5116             :  */
    5117             : bool
    5118         446 : pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
    5119             : {
    5120             :     HeapTuple   tuple;
    5121             :     Oid         ownerId;
    5122             : 
    5123             :     /* Superusers bypass all permission checking. */
    5124         446 :     if (superuser_arg(roleid))
    5125         280 :         return true;
    5126             : 
    5127         166 :     tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
    5128         166 :     if (!HeapTupleIsValid(tuple))
    5129           0 :         ereport(ERROR,
    5130             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5131             :                  errmsg("foreign server with OID %u does not exist",
    5132             :                         srv_oid)));
    5133             : 
    5134         166 :     ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
    5135             : 
    5136         166 :     ReleaseSysCache(tuple);
    5137             : 
    5138         166 :     return has_privs_of_role(roleid, ownerId);
    5139             : }
    5140             : 
    5141             : /*
    5142             :  * Ownership check for an event trigger (specified by OID).
    5143             :  */
    5144             : bool
    5145          92 : pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
    5146             : {
    5147             :     HeapTuple   tuple;
    5148             :     Oid         ownerId;
    5149             : 
    5150             :     /* Superusers bypass all permission checking. */
    5151          92 :     if (superuser_arg(roleid))
    5152          92 :         return true;
    5153             : 
    5154           0 :     tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
    5155           0 :     if (!HeapTupleIsValid(tuple))
    5156           0 :         ereport(ERROR,
    5157             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5158             :                  errmsg("event trigger with OID %u does not exist",
    5159             :                         et_oid)));
    5160             : 
    5161           0 :     ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
    5162             : 
    5163           0 :     ReleaseSysCache(tuple);
    5164             : 
    5165           0 :     return has_privs_of_role(roleid, ownerId);
    5166             : }
    5167             : 
    5168             : /*
    5169             :  * Ownership check for a database (specified by OID).
    5170             :  */
    5171             : bool
    5172        1770 : pg_database_ownercheck(Oid db_oid, Oid roleid)
    5173             : {
    5174             :     HeapTuple   tuple;
    5175             :     Oid         dba;
    5176             : 
    5177             :     /* Superusers bypass all permission checking. */
    5178        1770 :     if (superuser_arg(roleid))
    5179        1550 :         return true;
    5180             : 
    5181         220 :     tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
    5182         220 :     if (!HeapTupleIsValid(tuple))
    5183           0 :         ereport(ERROR,
    5184             :                 (errcode(ERRCODE_UNDEFINED_DATABASE),
    5185             :                  errmsg("database with OID %u does not exist", db_oid)));
    5186             : 
    5187         220 :     dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
    5188             : 
    5189         220 :     ReleaseSysCache(tuple);
    5190             : 
    5191         220 :     return has_privs_of_role(roleid, dba);
    5192             : }
    5193             : 
    5194             : /*
    5195             :  * Ownership check for a collation (specified by OID).
    5196             :  */
    5197             : bool
    5198           2 : pg_collation_ownercheck(Oid coll_oid, Oid roleid)
    5199             : {
    5200             :     HeapTuple   tuple;
    5201             :     Oid         ownerId;
    5202             : 
    5203             :     /* Superusers bypass all permission checking. */
    5204           2 :     if (superuser_arg(roleid))
    5205           2 :         return true;
    5206             : 
    5207           0 :     tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
    5208           0 :     if (!HeapTupleIsValid(tuple))
    5209           0 :         ereport(ERROR,
    5210             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5211             :                  errmsg("collation with OID %u does not exist", coll_oid)));
    5212             : 
    5213           0 :     ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
    5214             : 
    5215           0 :     ReleaseSysCache(tuple);
    5216             : 
    5217           0 :     return has_privs_of_role(roleid, ownerId);
    5218             : }
    5219             : 
    5220             : /*
    5221             :  * Ownership check for a conversion (specified by OID).
    5222             :  */
    5223             : bool
    5224          18 : pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
    5225             : {
    5226             :     HeapTuple   tuple;
    5227             :     Oid         ownerId;
    5228             : 
    5229             :     /* Superusers bypass all permission checking. */
    5230          18 :     if (superuser_arg(roleid))
    5231           2 :         return true;
    5232             : 
    5233          16 :     tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
    5234          16 :     if (!HeapTupleIsValid(tuple))
    5235           0 :         ereport(ERROR,
    5236             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5237             :                  errmsg("conversion with OID %u does not exist", conv_oid)));
    5238             : 
    5239          16 :     ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
    5240             : 
    5241          16 :     ReleaseSysCache(tuple);
    5242             : 
    5243          16 :     return has_privs_of_role(roleid, ownerId);
    5244             : }
    5245             : 
    5246             : /*
    5247             :  * Ownership check for an extension (specified by OID).
    5248             :  */
    5249             : bool
    5250         176 : pg_extension_ownercheck(Oid ext_oid, Oid roleid)
    5251             : {
    5252             :     Relation    pg_extension;
    5253             :     ScanKeyData entry[1];
    5254             :     SysScanDesc scan;
    5255             :     HeapTuple   tuple;
    5256             :     Oid         ownerId;
    5257             : 
    5258             :     /* Superusers bypass all permission checking. */
    5259         176 :     if (superuser_arg(roleid))
    5260         176 :         return true;
    5261             : 
    5262             :     /* There's no syscache for pg_extension, so do it the hard way */
    5263           0 :     pg_extension = table_open(ExtensionRelationId, AccessShareLock);
    5264             : 
    5265           0 :     ScanKeyInit(&entry[0],
    5266             :                 Anum_pg_extension_oid,
    5267             :                 BTEqualStrategyNumber, F_OIDEQ,
    5268             :                 ObjectIdGetDatum(ext_oid));
    5269             : 
    5270           0 :     scan = systable_beginscan(pg_extension,
    5271             :                               ExtensionOidIndexId, true,
    5272             :                               NULL, 1, entry);
    5273             : 
    5274           0 :     tuple = systable_getnext(scan);
    5275           0 :     if (!HeapTupleIsValid(tuple))
    5276           0 :         ereport(ERROR,
    5277             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5278             :                  errmsg("extension with OID %u does not exist", ext_oid)));
    5279             : 
    5280           0 :     ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
    5281             : 
    5282           0 :     systable_endscan(scan);
    5283           0 :     table_close(pg_extension, AccessShareLock);
    5284             : 
    5285           0 :     return has_privs_of_role(roleid, ownerId);
    5286             : }
    5287             : 
    5288             : /*
    5289             :  * Ownership check for a publication (specified by OID).
    5290             :  */
    5291             : bool
    5292         126 : pg_publication_ownercheck(Oid pub_oid, Oid roleid)
    5293             : {
    5294             :     HeapTuple   tuple;
    5295             :     Oid         ownerId;
    5296             : 
    5297             :     /* Superusers bypass all permission checking. */
    5298         126 :     if (superuser_arg(roleid))
    5299         114 :         return true;
    5300             : 
    5301          12 :     tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid));
    5302          12 :     if (!HeapTupleIsValid(tuple))
    5303           0 :         ereport(ERROR,
    5304             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5305             :                  errmsg("publication with OID %u does not exist", pub_oid)));
    5306             : 
    5307          12 :     ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner;
    5308             : 
    5309          12 :     ReleaseSysCache(tuple);
    5310             : 
    5311          12 :     return has_privs_of_role(roleid, ownerId);
    5312             : }
    5313             : 
    5314             : /*
    5315             :  * Ownership check for a subscription (specified by OID).
    5316             :  */
    5317             : bool
    5318         110 : pg_subscription_ownercheck(Oid sub_oid, Oid roleid)
    5319             : {
    5320             :     HeapTuple   tuple;
    5321             :     Oid         ownerId;
    5322             : 
    5323             :     /* Superusers bypass all permission checking. */
    5324         110 :     if (superuser_arg(roleid))
    5325         110 :         return true;
    5326             : 
    5327           0 :     tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid));
    5328           0 :     if (!HeapTupleIsValid(tuple))
    5329           0 :         ereport(ERROR,
    5330             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5331             :                  errmsg("subscription with OID %u does not exist", sub_oid)));
    5332             : 
    5333           0 :     ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner;
    5334             : 
    5335           0 :     ReleaseSysCache(tuple);
    5336             : 
    5337           0 :     return has_privs_of_role(roleid, ownerId);
    5338             : }
    5339             : 
    5340             : /*
    5341             :  * Ownership check for a statistics object (specified by OID).
    5342             :  */
    5343             : bool
    5344          14 : pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
    5345             : {
    5346             :     HeapTuple   tuple;
    5347             :     Oid         ownerId;
    5348             : 
    5349             :     /* Superusers bypass all permission checking. */
    5350          14 :     if (superuser_arg(roleid))
    5351          14 :         return true;
    5352             : 
    5353           0 :     tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid));
    5354           0 :     if (!HeapTupleIsValid(tuple))
    5355           0 :         ereport(ERROR,
    5356             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5357             :                  errmsg("statistics object with OID %u does not exist",
    5358             :                         stat_oid)));
    5359             : 
    5360           0 :     ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner;
    5361             : 
    5362           0 :     ReleaseSysCache(tuple);
    5363             : 
    5364           0 :     return has_privs_of_role(roleid, ownerId);
    5365             : }
    5366             : 
    5367             : /*
    5368             :  * Check whether specified role has CREATEROLE privilege (or is a superuser)
    5369             :  *
    5370             :  * Note: roles do not have owners per se; instead we use this test in
    5371             :  * places where an ownership-like permissions test is needed for a role.
    5372             :  * Be sure to apply it to the role trying to do the operation, not the
    5373             :  * role being operated on!  Also note that this generally should not be
    5374             :  * considered enough privilege if the target role is a superuser.
    5375             :  * (We don't handle that consideration here because we want to give a
    5376             :  * separate error message for such cases, so the caller has to deal with it.)
    5377             :  */
    5378             : bool
    5379        2598 : has_createrole_privilege(Oid roleid)
    5380             : {
    5381        2598 :     bool        result = false;
    5382             :     HeapTuple   utup;
    5383             : 
    5384             :     /* Superusers bypass all permission checking. */
    5385        2598 :     if (superuser_arg(roleid))
    5386        2556 :         return true;
    5387             : 
    5388          42 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    5389          42 :     if (HeapTupleIsValid(utup))
    5390             :     {
    5391          42 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
    5392          42 :         ReleaseSysCache(utup);
    5393             :     }
    5394          42 :     return result;
    5395             : }
    5396             : 
    5397             : bool
    5398        2472 : has_bypassrls_privilege(Oid roleid)
    5399             : {
    5400        2472 :     bool        result = false;
    5401             :     HeapTuple   utup;
    5402             : 
    5403             :     /* Superusers bypass all permission checking. */
    5404        2472 :     if (superuser_arg(roleid))
    5405         876 :         return true;
    5406             : 
    5407        1596 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    5408        1596 :     if (HeapTupleIsValid(utup))
    5409             :     {
    5410        1596 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
    5411        1596 :         ReleaseSysCache(utup);
    5412             :     }
    5413        1596 :     return result;
    5414             : }
    5415             : 
    5416             : /*
    5417             :  * Fetch pg_default_acl entry for given role, namespace and object type
    5418             :  * (object type must be given in pg_default_acl's encoding).
    5419             :  * Returns NULL if no such entry.
    5420             :  */
    5421             : static Acl *
    5422      162468 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
    5423             : {
    5424      162468 :     Acl        *result = NULL;
    5425             :     HeapTuple   tuple;
    5426             : 
    5427      162468 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    5428             :                             ObjectIdGetDatum(roleId),
    5429             :                             ObjectIdGetDatum(nsp_oid),
    5430             :                             CharGetDatum(objtype));
    5431             : 
    5432      162468 :     if (HeapTupleIsValid(tuple))
    5433             :     {
    5434             :         Datum       aclDatum;
    5435             :         bool        isNull;
    5436             : 
    5437         116 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    5438             :                                    Anum_pg_default_acl_defaclacl,
    5439             :                                    &isNull);
    5440         116 :         if (!isNull)
    5441         116 :             result = DatumGetAclPCopy(aclDatum);
    5442         116 :         ReleaseSysCache(tuple);
    5443             :     }
    5444             : 
    5445      162468 :     return result;
    5446             : }
    5447             : 
    5448             : /*
    5449             :  * Get default permissions for newly created object within given schema
    5450             :  *
    5451             :  * Returns NULL if built-in system defaults should be used.
    5452             :  *
    5453             :  * If the result is not NULL, caller must call recordDependencyOnNewAcl
    5454             :  * once the OID of the new object is known.
    5455             :  */
    5456             : Acl *
    5457       81234 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
    5458             : {
    5459             :     Acl        *result;
    5460             :     Acl        *glob_acl;
    5461             :     Acl        *schema_acl;
    5462             :     Acl        *def_acl;
    5463             :     char        defaclobjtype;
    5464             : 
    5465             :     /*
    5466             :      * Use NULL during bootstrap, since pg_default_acl probably isn't there
    5467             :      * yet.
    5468             :      */
    5469       81234 :     if (IsBootstrapProcessingMode())
    5470           0 :         return NULL;
    5471             : 
    5472             :     /* Check if object type is supported in pg_default_acl */
    5473       81234 :     switch (objtype)
    5474             :     {
    5475             :         case OBJECT_TABLE:
    5476       62594 :             defaclobjtype = DEFACLOBJ_RELATION;
    5477       62594 :             break;
    5478             : 
    5479             :         case OBJECT_SEQUENCE:
    5480         930 :             defaclobjtype = DEFACLOBJ_SEQUENCE;
    5481         930 :             break;
    5482             : 
    5483             :         case OBJECT_FUNCTION:
    5484       14082 :             defaclobjtype = DEFACLOBJ_FUNCTION;
    5485       14082 :             break;
    5486             : 
    5487             :         case OBJECT_TYPE:
    5488        2988 :             defaclobjtype = DEFACLOBJ_TYPE;
    5489        2988 :             break;
    5490             : 
    5491             :         case OBJECT_SCHEMA:
    5492         640 :             defaclobjtype = DEFACLOBJ_NAMESPACE;
    5493         640 :             break;
    5494             : 
    5495             :         default:
    5496           0 :             return NULL;
    5497             :     }
    5498             : 
    5499             :     /* Look up the relevant pg_default_acl entries */
    5500       81234 :     glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
    5501       81234 :     schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
    5502             : 
    5503             :     /* Quick out if neither entry exists */
    5504       81234 :     if (glob_acl == NULL && schema_acl == NULL)
    5505       81142 :         return NULL;
    5506             : 
    5507             :     /* We need to know the hard-wired default value, too */
    5508          92 :     def_acl = acldefault(objtype, ownerId);
    5509             : 
    5510             :     /* If there's no global entry, substitute the hard-wired default */
    5511          92 :     if (glob_acl == NULL)
    5512          12 :         glob_acl = def_acl;
    5513             : 
    5514             :     /* Merge in any per-schema privileges */
    5515          92 :     result = aclmerge(glob_acl, schema_acl, ownerId);
    5516             : 
    5517             :     /*
    5518             :      * For efficiency, we want to return NULL if the result equals default.
    5519             :      * This requires sorting both arrays to get an accurate comparison.
    5520             :      */
    5521          92 :     aclitemsort(result);
    5522          92 :     aclitemsort(def_acl);
    5523          92 :     if (aclequal(result, def_acl))
    5524          16 :         result = NULL;
    5525             : 
    5526          92 :     return result;
    5527             : }
    5528             : 
    5529             : /*
    5530             :  * Record dependencies on roles mentioned in a new object's ACL.
    5531             :  */
    5532             : void
    5533       83082 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
    5534             :                          Oid ownerId, Acl *acl)
    5535             : {
    5536             :     int         nmembers;
    5537             :     Oid        *members;
    5538             : 
    5539             :     /* Nothing to do if ACL is defaulted */
    5540       83082 :     if (acl == NULL)
    5541       83006 :         return;
    5542             : 
    5543             :     /* Extract roles mentioned in ACL */
    5544          76 :     nmembers = aclmembers(acl, &members);
    5545             : 
    5546             :     /* Update the shared dependency ACL info */
    5547          76 :     updateAclDependencies(classId, objectId, objsubId,
    5548             :                           ownerId,
    5549             :                           0, NULL,
    5550             :                           nmembers, members);
    5551             : }
    5552             : 
    5553             : /*
    5554             :  * Record initial privileges for the top-level object passed in.
    5555             :  *
    5556             :  * For the object passed in, this will record its ACL (if any) and the ACLs of
    5557             :  * any sub-objects (eg: columns) into pg_init_privs.
    5558             :  *
    5559             :  * Any new kinds of objects which have ACLs associated with them and can be
    5560             :  * added to an extension should be added to the if-else tree below.
    5561             :  */
    5562             : void
    5563          54 : recordExtObjInitPriv(Oid objoid, Oid classoid)
    5564             : {
    5565             :     /*
    5566             :      * pg_class / pg_attribute
    5567             :      *
    5568             :      * If this is a relation then we need to see if there are any sub-objects
    5569             :      * (eg: columns) for it and, if so, be sure to call
    5570             :      * recordExtensionInitPrivWorker() for each one.
    5571             :      */
    5572          54 :     if (classoid == RelationRelationId)
    5573             :     {
    5574             :         Form_pg_class pg_class_tuple;
    5575             :         Datum       aclDatum;
    5576             :         bool        isNull;
    5577             :         HeapTuple   tuple;
    5578             : 
    5579          14 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    5580          14 :         if (!HeapTupleIsValid(tuple))
    5581           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    5582          14 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    5583             : 
    5584             :         /* Indexes don't have permissions */
    5585          28 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    5586          14 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    5587           0 :             return;
    5588             : 
    5589             :         /* Composite types don't have permissions either */
    5590          14 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    5591           0 :             return;
    5592             : 
    5593             :         /*
    5594             :          * If this isn't a sequence, index, or composite type then it's
    5595             :          * possibly going to have columns associated with it that might have
    5596             :          * ACLs.
    5597             :          */
    5598          14 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    5599             :         {
    5600             :             AttrNumber  curr_att;
    5601          12 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    5602             : 
    5603          30 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    5604             :             {
    5605             :                 HeapTuple   attTuple;
    5606             :                 Datum       attaclDatum;
    5607             : 
    5608          18 :                 attTuple = SearchSysCache2(ATTNUM,
    5609             :                                            ObjectIdGetDatum(objoid),
    5610             :                                            Int16GetDatum(curr_att));
    5611             : 
    5612          18 :                 if (!HeapTupleIsValid(attTuple))
    5613           0 :                     continue;
    5614             : 
    5615             :                 /* ignore dropped columns */
    5616          18 :                 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    5617             :                 {
    5618           0 :                     ReleaseSysCache(attTuple);
    5619           0 :                     continue;
    5620             :                 }
    5621             : 
    5622          18 :                 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
    5623             :                                               Anum_pg_attribute_attacl,
    5624             :                                               &isNull);
    5625             : 
    5626             :                 /* no need to do anything for a NULL ACL */
    5627          18 :                 if (isNull)
    5628             :                 {
    5629          14 :                     ReleaseSysCache(attTuple);
    5630          14 :                     continue;
    5631             :                 }
    5632             : 
    5633           4 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
    5634           4 :                                               DatumGetAclP(attaclDatum));
    5635             : 
    5636           4 :                 ReleaseSysCache(attTuple);
    5637             :             }
    5638             :         }
    5639             : 
    5640          14 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    5641             :                                    &isNull);
    5642             : 
    5643             :         /* Add the record, if any, for the top-level object */
    5644          14 :         if (!isNull)
    5645           8 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5646           8 :                                           DatumGetAclP(aclDatum));
    5647             : 
    5648          14 :         ReleaseSysCache(tuple);
    5649             :     }
    5650             :     /* pg_foreign_data_wrapper */
    5651          40 :     else if (classoid == ForeignDataWrapperRelationId)
    5652             :     {
    5653             :         Datum       aclDatum;
    5654             :         bool        isNull;
    5655             :         HeapTuple   tuple;
    5656             : 
    5657           2 :         tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
    5658             :                                 ObjectIdGetDatum(objoid));
    5659           2 :         if (!HeapTupleIsValid(tuple))
    5660           0 :             elog(ERROR, "cache lookup failed for foreign data wrapper %u",
    5661             :                  objoid);
    5662             : 
    5663           2 :         aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
    5664             :                                    Anum_pg_foreign_data_wrapper_fdwacl,
    5665             :                                    &isNull);
    5666             : 
    5667             :         /* Add the record, if any, for the top-level object */
    5668           2 :         if (!isNull)
    5669           2 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5670           2 :                                           DatumGetAclP(aclDatum));
    5671             : 
    5672           2 :         ReleaseSysCache(tuple);
    5673             :     }
    5674             :     /* pg_foreign_server */
    5675          38 :     else if (classoid == ForeignServerRelationId)
    5676             :     {
    5677             :         Datum       aclDatum;
    5678             :         bool        isNull;
    5679             :         HeapTuple   tuple;
    5680             : 
    5681           2 :         tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid));
    5682           2 :         if (!HeapTupleIsValid(tuple))
    5683           0 :             elog(ERROR, "cache lookup failed for foreign data wrapper %u",
    5684             :                  objoid);
    5685             : 
    5686           2 :         aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
    5687             :                                    Anum_pg_foreign_server_srvacl,
    5688             :                                    &isNull);
    5689             : 
    5690             :         /* Add the record, if any, for the top-level object */
    5691           2 :         if (!isNull)
    5692           2 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5693           2 :                                           DatumGetAclP(aclDatum));
    5694             : 
    5695           2 :         ReleaseSysCache(tuple);
    5696             :     }
    5697             :     /* pg_language */
    5698          36 :     else if (classoid == LanguageRelationId)
    5699             :     {
    5700             :         Datum       aclDatum;
    5701             :         bool        isNull;
    5702             :         HeapTuple   tuple;
    5703             : 
    5704           0 :         tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
    5705           0 :         if (!HeapTupleIsValid(tuple))
    5706           0 :             elog(ERROR, "cache lookup failed for language %u", objoid);
    5707             : 
    5708           0 :         aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
    5709             :                                    &isNull);
    5710             : 
    5711             :         /* Add the record, if any, for the top-level object */
    5712           0 :         if (!isNull)
    5713           0 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5714           0 :                                           DatumGetAclP(aclDatum));
    5715             : 
    5716           0 :         ReleaseSysCache(tuple);
    5717             :     }
    5718             :     /* pg_largeobject_metadata */
    5719          36 :     else if (classoid == LargeObjectMetadataRelationId)
    5720             :     {
    5721             :         Datum       aclDatum;
    5722             :         bool        isNull;
    5723             :         HeapTuple   tuple;
    5724             :         ScanKeyData entry[1];
    5725             :         SysScanDesc scan;
    5726             :         Relation    relation;
    5727             : 
    5728           0 :         relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
    5729             : 
    5730             :         /* There's no syscache for pg_largeobject_metadata */
    5731           0 :         ScanKeyInit(&entry[0],
    5732             :                     Anum_pg_largeobject_metadata_oid,
    5733             :                     BTEqualStrategyNumber, F_OIDEQ,
    5734             :                     ObjectIdGetDatum(objoid));
    5735             : 
    5736           0 :         scan = systable_beginscan(relation,
    5737             :                                   LargeObjectMetadataOidIndexId, true,
    5738             :                                   NULL, 1, entry);
    5739             : 
    5740           0 :         tuple = systable_getnext(scan);
    5741           0 :         if (!HeapTupleIsValid(tuple))
    5742           0 :             elog(ERROR, "could not find tuple for large object %u", objoid);
    5743             : 
    5744           0 :         aclDatum = heap_getattr(tuple,
    5745             :                                 Anum_pg_largeobject_metadata_lomacl,
    5746             :                                 RelationGetDescr(relation), &isNull);
    5747             : 
    5748             :         /* Add the record, if any, for the top-level object */
    5749           0 :         if (!isNull)
    5750           0 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5751           0 :                                           DatumGetAclP(aclDatum));
    5752             : 
    5753           0 :         systable_endscan(scan);
    5754             :     }
    5755             :     /* pg_namespace */
    5756          36 :     else if (classoid == NamespaceRelationId)
    5757             :     {
    5758             :         Datum       aclDatum;
    5759             :         bool        isNull;
    5760             :         HeapTuple   tuple;
    5761             : 
    5762           2 :         tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid));
    5763           2 :         if (!HeapTupleIsValid(tuple))
    5764           0 :             elog(ERROR, "cache lookup failed for function %u", objoid);
    5765             : 
    5766           2 :         aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple,
    5767             :                                    Anum_pg_namespace_nspacl, &isNull);
    5768             : 
    5769             :         /* Add the record, if any, for the top-level object */
    5770           2 :         if (!isNull)
    5771           2 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5772           2 :                                           DatumGetAclP(aclDatum));
    5773             : 
    5774           2 :         ReleaseSysCache(tuple);
    5775             :     }
    5776             :     /* pg_proc */
    5777          34 :     else if (classoid == ProcedureRelationId)
    5778             :     {
    5779             :         Datum       aclDatum;
    5780             :         bool        isNull;
    5781             :         HeapTuple   tuple;
    5782             : 
    5783          12 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid));
    5784          12 :         if (!HeapTupleIsValid(tuple))
    5785           0 :             elog(ERROR, "cache lookup failed for function %u", objoid);
    5786             : 
    5787          12 :         aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
    5788             :                                    &isNull);
    5789             : 
    5790             :         /* Add the record, if any, for the top-level object */
    5791          12 :         if (!isNull)
    5792           2 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5793           2 :                                           DatumGetAclP(aclDatum));
    5794             : 
    5795          12 :         ReleaseSysCache(tuple);
    5796             :     }
    5797             :     /* pg_type */
    5798          22 :     else if (classoid == TypeRelationId)
    5799             :     {
    5800             :         Datum       aclDatum;
    5801             :         bool        isNull;
    5802             :         HeapTuple   tuple;
    5803             : 
    5804           2 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid));
    5805           2 :         if (!HeapTupleIsValid(tuple))
    5806           0 :             elog(ERROR, "cache lookup failed for function %u", objoid);
    5807             : 
    5808           2 :         aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl,
    5809             :                                    &isNull);
    5810             : 
    5811             :         /* Add the record, if any, for the top-level object */
    5812           2 :         if (!isNull)
    5813           2 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    5814           2 :                                           DatumGetAclP(aclDatum));
    5815             : 
    5816           2 :         ReleaseSysCache(tuple);
    5817             :     }
    5818          20 :     else if (classoid == AccessMethodRelationId ||
    5819          18 :              classoid == AggregateRelationId ||
    5820          16 :              classoid == CastRelationId ||
    5821          16 :              classoid == CollationRelationId ||
    5822          16 :              classoid == ConversionRelationId ||
    5823          16 :              classoid == EventTriggerRelationId ||
    5824           6 :              classoid == OperatorRelationId ||
    5825           4 :              classoid == OperatorClassRelationId ||
    5826           2 :              classoid == OperatorFamilyRelationId ||
    5827           2 :              classoid == NamespaceRelationId ||
    5828           2 :              classoid == TSConfigRelationId ||
    5829           2 :              classoid == TSDictionaryRelationId ||
    5830           2 :              classoid == TSParserRelationId ||
    5831           2 :              classoid == TSTemplateRelationId ||
    5832             :              classoid == TransformRelationId
    5833             :         )
    5834             :     {
    5835             :         /* no ACL for these object types, so do nothing. */
    5836             :     }
    5837             : 
    5838             :     /*
    5839             :      * complain if we are given a class OID for a class that extensions don't
    5840             :      * support or that we don't recognize.
    5841             :      */
    5842             :     else
    5843             :     {
    5844           0 :         elog(ERROR, "unrecognized or unsupported class OID: %u", classoid);
    5845             :     }
    5846             : }
    5847             : 
    5848             : /*
    5849             :  * For the object passed in, remove its ACL and the ACLs of any object subIds
    5850             :  * from pg_init_privs (via recordExtensionInitPrivWorker()).
    5851             :  */
    5852             : void
    5853          64 : removeExtObjInitPriv(Oid objoid, Oid classoid)
    5854             : {
    5855             :     /*
    5856             :      * If this is a relation then we need to see if there are any sub-objects
    5857             :      * (eg: columns) for it and, if so, be sure to call
    5858             :      * recordExtensionInitPrivWorker() for each one.
    5859             :      */
    5860          64 :     if (classoid == RelationRelationId)
    5861             :     {
    5862             :         Form_pg_class pg_class_tuple;
    5863             :         HeapTuple   tuple;
    5864             : 
    5865           8 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    5866           8 :         if (!HeapTupleIsValid(tuple))
    5867           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    5868           8 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    5869             : 
    5870             :         /* Indexes don't have permissions */
    5871          16 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    5872           8 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    5873           0 :             return;
    5874             : 
    5875             :         /* Composite types don't have permissions either */
    5876           8 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    5877           0 :             return;
    5878             : 
    5879             :         /*
    5880             :          * If this isn't a sequence, index, or composite type then it's
    5881             :          * possibly going to have columns associated with it that might have
    5882             :          * ACLs.
    5883             :          */
    5884           8 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    5885             :         {
    5886             :             AttrNumber  curr_att;
    5887           8 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    5888             : 
    5889          20 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    5890             :             {
    5891             :                 HeapTuple   attTuple;
    5892             : 
    5893          12 :                 attTuple = SearchSysCache2(ATTNUM,
    5894             :                                            ObjectIdGetDatum(objoid),
    5895             :                                            Int16GetDatum(curr_att));
    5896             : 
    5897          12 :                 if (!HeapTupleIsValid(attTuple))
    5898           0 :                     continue;
    5899             : 
    5900             :                 /* when removing, remove all entries, even dropped columns */
    5901             : 
    5902          12 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
    5903             : 
    5904          12 :                 ReleaseSysCache(attTuple);
    5905             :             }
    5906             :         }
    5907             : 
    5908           8 :         ReleaseSysCache(tuple);
    5909             :     }
    5910             : 
    5911             :     /* Remove the record, if any, for the top-level object */
    5912          64 :     recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
    5913             : }
    5914             : 
    5915             : /*
    5916             :  * Record initial ACL for an extension object
    5917             :  *
    5918             :  * Can be called at any time, we check if 'creating_extension' is set and, if
    5919             :  * not, exit immediately.
    5920             :  *
    5921             :  * Pass in the object OID, the OID of the class (the OID of the table which
    5922             :  * the object is defined in) and the 'sub' id of the object (objsubid), if
    5923             :  * any.  If there is no 'sub' id (they are currently only used for columns of
    5924             :  * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
    5925             :  *
    5926             :  * If an ACL already exists for this object/sub-object then we will replace
    5927             :  * it with what is passed in.
    5928             :  *
    5929             :  * Passing in NULL for 'new_acl' will result in the entry for the object being
    5930             :  * removed, if one is found.
    5931             :  */
    5932             : static void
    5933       40678 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    5934             : {
    5935             :     /*
    5936             :      * Generally, we only record the initial privileges when an extension is
    5937             :      * being created, but because we don't actually use CREATE EXTENSION
    5938             :      * during binary upgrades with pg_upgrade, there is a variable to let us
    5939             :      * know that the GRANT and REVOKE statements being issued, while this
    5940             :      * variable is true, are for the initial privileges of the extension
    5941             :      * object and therefore we need to record them.
    5942             :      */
    5943       40678 :     if (!creating_extension && !binary_upgrade_record_init_privs)
    5944       40524 :         return;
    5945             : 
    5946         154 :     recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
    5947             : }
    5948             : 
    5949             : /*
    5950             :  * Record initial ACL for an extension object, worker.
    5951             :  *
    5952             :  * This will perform a wholesale replacement of the entire ACL for the object
    5953             :  * passed in, therefore be sure to pass in the complete new ACL to use.
    5954             :  *
    5955             :  * Generally speaking, do *not* use this function directly but instead use
    5956             :  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
    5957             :  * This function does *not* check if 'creating_extension' is set as it is also
    5958             :  * used when an object is added to or removed from an extension via ALTER
    5959             :  * EXTENSION ... ADD/DROP.
    5960             :  */
    5961             : static void
    5962         252 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    5963             : {
    5964             :     Relation    relation;
    5965             :     ScanKeyData key[3];
    5966             :     SysScanDesc scan;
    5967             :     HeapTuple   tuple;
    5968             :     HeapTuple   oldtuple;
    5969             : 
    5970         252 :     relation = table_open(InitPrivsRelationId, RowExclusiveLock);
    5971             : 
    5972         252 :     ScanKeyInit(&key[0],
    5973             :                 Anum_pg_init_privs_objoid,
    5974             :                 BTEqualStrategyNumber, F_OIDEQ,
    5975             :                 ObjectIdGetDatum(objoid));
    5976         252 :     ScanKeyInit(&key[1],
    5977             :                 Anum_pg_init_privs_classoid,
    5978             :                 BTEqualStrategyNumber, F_OIDEQ,
    5979             :                 ObjectIdGetDatum(classoid));
    5980         252 :     ScanKeyInit(&key[2],
    5981             :                 Anum_pg_init_privs_objsubid,
    5982             :                 BTEqualStrategyNumber, F_INT4EQ,
    5983             :                 Int32GetDatum(objsubid));
    5984             : 
    5985         252 :     scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
    5986             :                               NULL, 3, key);
    5987             : 
    5988             :     /* There should exist only one entry or none. */
    5989         252 :     oldtuple = systable_getnext(scan);
    5990             : 
    5991             :     /* If we find an entry, update it with the latest ACL. */
    5992         252 :     if (HeapTupleIsValid(oldtuple))
    5993             :     {
    5994             :         Datum       values[Natts_pg_init_privs];
    5995             :         bool        nulls[Natts_pg_init_privs];
    5996             :         bool        replace[Natts_pg_init_privs];
    5997             : 
    5998             :         /* If we have a new ACL to set, then update the row with it. */
    5999          70 :         if (new_acl)
    6000             :         {
    6001          42 :             MemSet(values, 0, sizeof(values));
    6002          42 :             MemSet(nulls, false, sizeof(nulls));
    6003          42 :             MemSet(replace, false, sizeof(replace));
    6004             : 
    6005          42 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    6006          42 :             replace[Anum_pg_init_privs_initprivs - 1] = true;
    6007             : 
    6008          42 :             oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
    6009             :                                          values, nulls, replace);
    6010             : 
    6011          42 :             CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
    6012             :         }
    6013             :         else
    6014             :         {
    6015             :             /* new_acl is NULL, so delete the entry we found. */
    6016          28 :             CatalogTupleDelete(relation, &oldtuple->t_self);
    6017             :         }
    6018             :     }
    6019             :     else
    6020             :     {
    6021             :         Datum       values[Natts_pg_init_privs];
    6022             :         bool        nulls[Natts_pg_init_privs];
    6023             : 
    6024             :         /*
    6025             :          * Only add a new entry if the new ACL is non-NULL.
    6026             :          *
    6027             :          * If we are passed in a NULL ACL and no entry exists, we can just
    6028             :          * fall through and do nothing.
    6029             :          */
    6030         182 :         if (new_acl)
    6031             :         {
    6032             :             /* No entry found, so add it. */
    6033         130 :             MemSet(nulls, false, sizeof(nulls));
    6034             : 
    6035         130 :             values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
    6036         130 :             values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
    6037         130 :             values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
    6038             : 
    6039             :             /* This function only handles initial privileges of extensions */
    6040         130 :             values[Anum_pg_init_privs_privtype - 1] =
    6041             :                 CharGetDatum(INITPRIVS_EXTENSION);
    6042             : 
    6043         130 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    6044             : 
    6045         130 :             tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
    6046             : 
    6047         130 :             CatalogTupleInsert(relation, tuple);
    6048             :         }
    6049             :     }
    6050             : 
    6051         252 :     systable_endscan(scan);
    6052             : 
    6053             :     /* prevent error when processing objects multiple times */
    6054         252 :     CommandCounterIncrement();
    6055             : 
    6056         252 :     table_close(relation, RowExclusiveLock);
    6057         252 : }

Generated by: LCOV version 1.13