LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 70.9 % 2293 1625
Test Date: 2026-01-26 10:56:24 Functions: 83.1 % 59 49
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 49.0 % 1308 641

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

Generated by: LCOV version 2.3.2-1