LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 1626 2031 80.1 %
Date: 2019-09-22 07:07:17 Functions: 83 85 97.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13