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

Generated by: LCOV version 1.11