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

Generated by: LCOV version 1.13