LCOV - code coverage report
Current view: top level - src/backend/utils/adt - acl.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 1121 1871 59.9 %
Date: 2024-04-18 05:10:52 Functions: 104 166 62.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * acl.c
       4             :  *    Basic access control list data structures manipulation routines.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/adt/acl.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include <ctype.h>
      18             : 
      19             : #include "access/htup_details.h"
      20             : #include "catalog/catalog.h"
      21             : #include "catalog/namespace.h"
      22             : #include "catalog/pg_auth_members.h"
      23             : #include "catalog/pg_authid.h"
      24             : #include "catalog/pg_class.h"
      25             : #include "catalog/pg_database.h"
      26             : #include "catalog/pg_foreign_data_wrapper.h"
      27             : #include "catalog/pg_foreign_server.h"
      28             : #include "catalog/pg_language.h"
      29             : #include "catalog/pg_namespace.h"
      30             : #include "catalog/pg_proc.h"
      31             : #include "catalog/pg_tablespace.h"
      32             : #include "catalog/pg_type.h"
      33             : #include "commands/dbcommands.h"
      34             : #include "commands/proclang.h"
      35             : #include "commands/tablespace.h"
      36             : #include "common/hashfn.h"
      37             : #include "foreign/foreign.h"
      38             : #include "funcapi.h"
      39             : #include "lib/bloomfilter.h"
      40             : #include "lib/qunique.h"
      41             : #include "miscadmin.h"
      42             : #include "utils/acl.h"
      43             : #include "utils/array.h"
      44             : #include "utils/builtins.h"
      45             : #include "utils/catcache.h"
      46             : #include "utils/inval.h"
      47             : #include "utils/lsyscache.h"
      48             : #include "utils/memutils.h"
      49             : #include "utils/syscache.h"
      50             : #include "utils/varlena.h"
      51             : 
      52             : typedef struct
      53             : {
      54             :     const char *name;
      55             :     AclMode     value;
      56             : } priv_map;
      57             : 
      58             : /*
      59             :  * We frequently need to test whether a given role is a member of some other
      60             :  * role.  In most of these tests the "given role" is the same, namely the
      61             :  * active current user.  So we can optimize it by keeping cached lists of all
      62             :  * the roles the "given role" is a member of, directly or indirectly.
      63             :  *
      64             :  * Possibly this mechanism should be generalized to allow caching membership
      65             :  * info for multiple roles?
      66             :  *
      67             :  * Each element of cached_roles is an OID list of constituent roles for the
      68             :  * corresponding element of cached_role (always including the cached_role
      69             :  * itself).  There's a separate cache for each RoleRecurseType, with the
      70             :  * corresponding semantics.
      71             :  */
      72             : enum RoleRecurseType
      73             : {
      74             :     ROLERECURSE_MEMBERS = 0,    /* recurse unconditionally */
      75             :     ROLERECURSE_PRIVS = 1,      /* recurse through inheritable grants */
      76             :     ROLERECURSE_SETROLE = 2     /* recurse through grants with set_option */
      77             : };
      78             : static Oid  cached_role[] = {InvalidOid, InvalidOid, InvalidOid};
      79             : static List *cached_roles[] = {NIL, NIL, NIL};
      80             : static uint32 cached_db_hash;
      81             : 
      82             : /*
      83             :  * If the list of roles gathered by roles_is_member_of() grows larger than the
      84             :  * below threshold, a Bloom filter is created to speed up list membership
      85             :  * checks.  This threshold is set arbitrarily high to avoid the overhead of
      86             :  * creating the Bloom filter until it seems likely to provide a net benefit.
      87             :  */
      88             : #define ROLES_LIST_BLOOM_THRESHOLD 1024
      89             : 
      90             : static const char *getid(const char *s, char *n, Node *escontext);
      91             : static void putid(char *p, const char *s);
      92             : static Acl *allocacl(int n);
      93             : static void check_acl(const Acl *acl);
      94             : static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
      95             : static bool aclitem_match(const AclItem *a1, const AclItem *a2);
      96             : static int  aclitemComparator(const void *arg1, const void *arg2);
      97             : static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
      98             :                               Oid ownerId);
      99             : static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
     100             :                              Oid ownerId, DropBehavior behavior);
     101             : 
     102             : static AclMode convert_any_priv_string(text *priv_type_text,
     103             :                                        const priv_map *privileges);
     104             : 
     105             : static Oid  convert_table_name(text *tablename);
     106             : static AclMode convert_table_priv_string(text *priv_type_text);
     107             : static AclMode convert_sequence_priv_string(text *priv_type_text);
     108             : static AttrNumber convert_column_name(Oid tableoid, text *column);
     109             : static AclMode convert_column_priv_string(text *priv_type_text);
     110             : static Oid  convert_database_name(text *databasename);
     111             : static AclMode convert_database_priv_string(text *priv_type_text);
     112             : static Oid  convert_foreign_data_wrapper_name(text *fdwname);
     113             : static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
     114             : static Oid  convert_function_name(text *functionname);
     115             : static AclMode convert_function_priv_string(text *priv_type_text);
     116             : static Oid  convert_language_name(text *languagename);
     117             : static AclMode convert_language_priv_string(text *priv_type_text);
     118             : static Oid  convert_schema_name(text *schemaname);
     119             : static AclMode convert_schema_priv_string(text *priv_type_text);
     120             : static Oid  convert_server_name(text *servername);
     121             : static AclMode convert_server_priv_string(text *priv_type_text);
     122             : static Oid  convert_tablespace_name(text *tablespacename);
     123             : static AclMode convert_tablespace_priv_string(text *priv_type_text);
     124             : static Oid  convert_type_name(text *typename);
     125             : static AclMode convert_type_priv_string(text *priv_type_text);
     126             : static AclMode convert_parameter_priv_string(text *priv_text);
     127             : static AclMode convert_role_priv_string(text *priv_type_text);
     128             : static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
     129             : 
     130             : static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
     131             : 
     132             : 
     133             : /*
     134             :  * getid
     135             :  *      Consumes the first alphanumeric string (identifier) found in string
     136             :  *      's', ignoring any leading white space.  If it finds a double quote
     137             :  *      it returns the word inside the quotes.
     138             :  *
     139             :  * RETURNS:
     140             :  *      the string position in 's' that points to the next non-space character
     141             :  *      in 's', after any quotes.  Also:
     142             :  *      - loads the identifier into 'n'.  (If no identifier is found, 'n'
     143             :  *        contains an empty string.)  'n' must be NAMEDATALEN bytes.
     144             :  *
     145             :  * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
     146             :  * in which case we log the error there and return NULL.
     147             :  */
     148             : static const char *
     149         236 : getid(const char *s, char *n, Node *escontext)
     150             : {
     151         236 :     int         len = 0;
     152         236 :     bool        in_quotes = false;
     153             : 
     154             :     Assert(s && n);
     155             : 
     156         236 :     while (isspace((unsigned char) *s))
     157           0 :         s++;
     158             :     /* This code had better match what putid() does, below */
     159         236 :     for (;
     160        2196 :          *s != '\0' &&
     161        2084 :          (isalnum((unsigned char) *s) ||
     162         410 :           *s == '_' ||
     163         276 :           *s == '"' ||
     164             :           in_quotes);
     165        1960 :          s++)
     166             :     {
     167        1960 :         if (*s == '"')
     168             :         {
     169             :             /* safe to look at next char (could be '\0' though) */
     170         152 :             if (*(s + 1) != '"')
     171             :             {
     172         152 :                 in_quotes = !in_quotes;
     173         152 :                 continue;
     174             :             }
     175             :             /* it's an escaped double quote; skip the escaping char */
     176           0 :             s++;
     177             :         }
     178             : 
     179             :         /* Add the character to the string */
     180        1808 :         if (len >= NAMEDATALEN - 1)
     181           0 :             ereturn(escontext, NULL,
     182             :                     (errcode(ERRCODE_NAME_TOO_LONG),
     183             :                      errmsg("identifier too long"),
     184             :                      errdetail("Identifier must be less than %d characters.",
     185             :                                NAMEDATALEN)));
     186             : 
     187        1808 :         n[len++] = *s;
     188             :     }
     189         236 :     n[len] = '\0';
     190         236 :     while (isspace((unsigned char) *s))
     191           0 :         s++;
     192         236 :     return s;
     193             : }
     194             : 
     195             : /*
     196             :  * Write a role name at *p, adding double quotes if needed.
     197             :  * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
     198             :  * This needs to be kept in sync with dequoteAclUserName in pg_dump/dumputils.c
     199             :  */
     200             : static void
     201     1056034 : putid(char *p, const char *s)
     202             : {
     203             :     const char *src;
     204     1056034 :     bool        safe = true;
     205             : 
     206     9993970 :     for (src = s; *src; src++)
     207             :     {
     208             :         /* This test had better match what getid() does, above */
     209     8938308 :         if (!isalnum((unsigned char) *src) && *src != '_')
     210             :         {
     211         372 :             safe = false;
     212         372 :             break;
     213             :         }
     214             :     }
     215     1056034 :     if (!safe)
     216         372 :         *p++ = '"';
     217     9997318 :     for (src = s; *src; src++)
     218             :     {
     219             :         /* A double quote character in a username is encoded as "" */
     220     8941284 :         if (*src == '"')
     221         372 :             *p++ = '"';
     222     8941284 :         *p++ = *src;
     223             :     }
     224     1056034 :     if (!safe)
     225         372 :         *p++ = '"';
     226     1056034 :     *p = '\0';
     227     1056034 : }
     228             : 
     229             : /*
     230             :  * aclparse
     231             :  *      Consumes and parses an ACL specification of the form:
     232             :  *              [group|user] [A-Za-z0-9]*=[rwaR]*
     233             :  *      from string 's', ignoring any leading white space or white space
     234             :  *      between the optional id type keyword (group|user) and the actual
     235             :  *      ACL specification.
     236             :  *
     237             :  *      The group|user decoration is unnecessary in the roles world,
     238             :  *      but we still accept it for backward compatibility.
     239             :  *
     240             :  *      This routine is called by the parser as well as aclitemin(), hence
     241             :  *      the added generality.
     242             :  *
     243             :  * RETURNS:
     244             :  *      the string position in 's' immediately following the ACL
     245             :  *      specification.  Also:
     246             :  *      - loads the structure pointed to by 'aip' with the appropriate
     247             :  *        UID/GID, id type identifier and mode type values.
     248             :  *
     249             :  * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
     250             :  * in which case we log the error there and return NULL.
     251             :  */
     252             : static const char *
     253         124 : aclparse(const char *s, AclItem *aip, Node *escontext)
     254             : {
     255             :     AclMode     privs,
     256             :                 goption,
     257             :                 read;
     258             :     char        name[NAMEDATALEN];
     259             :     char        name2[NAMEDATALEN];
     260             : 
     261             :     Assert(s && aip);
     262             : 
     263         124 :     s = getid(s, name, escontext);
     264         124 :     if (s == NULL)
     265           0 :         return NULL;
     266         124 :     if (*s != '=')
     267             :     {
     268             :         /* we just read a keyword, not a name */
     269           0 :         if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
     270           0 :             ereturn(escontext, NULL,
     271             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     272             :                      errmsg("unrecognized key word: \"%s\"", name),
     273             :                      errhint("ACL key word must be \"group\" or \"user\".")));
     274             :         /* move s to the name beyond the keyword */
     275           0 :         s = getid(s, name, escontext);
     276           0 :         if (s == NULL)
     277           0 :             return NULL;
     278           0 :         if (name[0] == '\0')
     279           0 :             ereturn(escontext, NULL,
     280             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     281             :                      errmsg("missing name"),
     282             :                      errhint("A name must follow the \"group\" or \"user\" key word.")));
     283             :     }
     284             : 
     285         124 :     if (*s != '=')
     286           0 :         ereturn(escontext, NULL,
     287             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     288             :                  errmsg("missing \"=\" sign")));
     289             : 
     290         124 :     privs = goption = ACL_NO_RIGHTS;
     291             : 
     292         254 :     for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
     293             :     {
     294         142 :         switch (*s)
     295             :         {
     296           0 :             case '*':
     297           0 :                 goption |= read;
     298           0 :                 break;
     299           0 :             case ACL_INSERT_CHR:
     300           0 :                 read = ACL_INSERT;
     301           0 :                 break;
     302         118 :             case ACL_SELECT_CHR:
     303         118 :                 read = ACL_SELECT;
     304         118 :                 break;
     305           0 :             case ACL_UPDATE_CHR:
     306           0 :                 read = ACL_UPDATE;
     307           0 :                 break;
     308           0 :             case ACL_DELETE_CHR:
     309           0 :                 read = ACL_DELETE;
     310           0 :                 break;
     311           0 :             case ACL_TRUNCATE_CHR:
     312           0 :                 read = ACL_TRUNCATE;
     313           0 :                 break;
     314           0 :             case ACL_REFERENCES_CHR:
     315           0 :                 read = ACL_REFERENCES;
     316           0 :                 break;
     317           0 :             case ACL_TRIGGER_CHR:
     318           0 :                 read = ACL_TRIGGER;
     319           0 :                 break;
     320           0 :             case ACL_EXECUTE_CHR:
     321           0 :                 read = ACL_EXECUTE;
     322           0 :                 break;
     323           6 :             case ACL_USAGE_CHR:
     324           6 :                 read = ACL_USAGE;
     325           6 :                 break;
     326           6 :             case ACL_CREATE_CHR:
     327           6 :                 read = ACL_CREATE;
     328           6 :                 break;
     329           0 :             case ACL_CREATE_TEMP_CHR:
     330           0 :                 read = ACL_CREATE_TEMP;
     331           0 :                 break;
     332           0 :             case ACL_CONNECT_CHR:
     333           0 :                 read = ACL_CONNECT;
     334           0 :                 break;
     335           0 :             case ACL_SET_CHR:
     336           0 :                 read = ACL_SET;
     337           0 :                 break;
     338           0 :             case ACL_ALTER_SYSTEM_CHR:
     339           0 :                 read = ACL_ALTER_SYSTEM;
     340           0 :                 break;
     341           0 :             case ACL_MAINTAIN_CHR:
     342           0 :                 read = ACL_MAINTAIN;
     343           0 :                 break;
     344           0 :             case 'R':           /* ignore old RULE privileges */
     345           0 :                 read = 0;
     346           0 :                 break;
     347          12 :             default:
     348          12 :                 ereturn(escontext, NULL,
     349             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     350             :                          errmsg("invalid mode character: must be one of \"%s\"",
     351             :                                 ACL_ALL_RIGHTS_STR)));
     352             :         }
     353             : 
     354         130 :         privs |= read;
     355             :     }
     356             : 
     357         112 :     if (name[0] == '\0')
     358          76 :         aip->ai_grantee = ACL_ID_PUBLIC;
     359             :     else
     360             :     {
     361          36 :         aip->ai_grantee = get_role_oid(name, true);
     362          36 :         if (!OidIsValid(aip->ai_grantee))
     363           0 :             ereturn(escontext, NULL,
     364             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     365             :                      errmsg("role \"%s\" does not exist", name)));
     366             :     }
     367             : 
     368             :     /*
     369             :      * XXX Allow a degree of backward compatibility by defaulting the grantor
     370             :      * to the superuser.
     371             :      */
     372         112 :     if (*s == '/')
     373             :     {
     374         112 :         s = getid(s + 1, name2, escontext);
     375         112 :         if (s == NULL)
     376           0 :             return NULL;
     377         112 :         if (name2[0] == '\0')
     378          12 :             ereturn(escontext, NULL,
     379             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     380             :                      errmsg("a name must follow the \"/\" sign")));
     381         100 :         aip->ai_grantor = get_role_oid(name2, true);
     382         100 :         if (!OidIsValid(aip->ai_grantor))
     383          12 :             ereturn(escontext, NULL,
     384             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     385             :                      errmsg("role \"%s\" does not exist", name2)));
     386             :     }
     387             :     else
     388             :     {
     389           0 :         aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
     390           0 :         ereport(WARNING,
     391             :                 (errcode(ERRCODE_INVALID_GRANTOR),
     392             :                  errmsg("defaulting grantor to user ID %u",
     393             :                         BOOTSTRAP_SUPERUSERID)));
     394             :     }
     395             : 
     396          88 :     ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
     397             : 
     398          88 :     return s;
     399             : }
     400             : 
     401             : /*
     402             :  * allocacl
     403             :  *      Allocates storage for a new Acl with 'n' entries.
     404             :  *
     405             :  * RETURNS:
     406             :  *      the new Acl
     407             :  */
     408             : static Acl *
     409      445892 : allocacl(int n)
     410             : {
     411             :     Acl        *new_acl;
     412             :     Size        size;
     413             : 
     414      445892 :     if (n < 0)
     415           0 :         elog(ERROR, "invalid size: %d", n);
     416      445892 :     size = ACL_N_SIZE(n);
     417      445892 :     new_acl = (Acl *) palloc0(size);
     418      445892 :     SET_VARSIZE(new_acl, size);
     419      445892 :     new_acl->ndim = 1;
     420      445892 :     new_acl->dataoffset = 0; /* we never put in any nulls */
     421      445892 :     new_acl->elemtype = ACLITEMOID;
     422      445892 :     ARR_LBOUND(new_acl)[0] = 1;
     423      445892 :     ARR_DIMS(new_acl)[0] = n;
     424      445892 :     return new_acl;
     425             : }
     426             : 
     427             : /*
     428             :  * Create a zero-entry ACL
     429             :  */
     430             : Acl *
     431          60 : make_empty_acl(void)
     432             : {
     433          60 :     return allocacl(0);
     434             : }
     435             : 
     436             : /*
     437             :  * Copy an ACL
     438             :  */
     439             : Acl *
     440        8274 : aclcopy(const Acl *orig_acl)
     441             : {
     442             :     Acl        *result_acl;
     443             : 
     444        8274 :     result_acl = allocacl(ACL_NUM(orig_acl));
     445             : 
     446        8274 :     memcpy(ACL_DAT(result_acl),
     447        8274 :            ACL_DAT(orig_acl),
     448        8274 :            ACL_NUM(orig_acl) * sizeof(AclItem));
     449             : 
     450        8274 :     return result_acl;
     451             : }
     452             : 
     453             : /*
     454             :  * Concatenate two ACLs
     455             :  *
     456             :  * This is a bit cheesy, since we may produce an ACL with redundant entries.
     457             :  * Be careful what the result is used for!
     458             :  */
     459             : Acl *
     460       17794 : aclconcat(const Acl *left_acl, const Acl *right_acl)
     461             : {
     462             :     Acl        *result_acl;
     463             : 
     464       17794 :     result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
     465             : 
     466       17794 :     memcpy(ACL_DAT(result_acl),
     467       17794 :            ACL_DAT(left_acl),
     468       17794 :            ACL_NUM(left_acl) * sizeof(AclItem));
     469             : 
     470       17794 :     memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
     471       17794 :            ACL_DAT(right_acl),
     472       17794 :            ACL_NUM(right_acl) * sizeof(AclItem));
     473             : 
     474       17794 :     return result_acl;
     475             : }
     476             : 
     477             : /*
     478             :  * Merge two ACLs
     479             :  *
     480             :  * This produces a properly merged ACL with no redundant entries.
     481             :  * Returns NULL on NULL input.
     482             :  */
     483             : Acl *
     484         192 : aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
     485             : {
     486             :     Acl        *result_acl;
     487             :     AclItem    *aip;
     488             :     int         i,
     489             :                 num;
     490             : 
     491             :     /* Check for cases where one or both are empty/null */
     492         192 :     if (left_acl == NULL || ACL_NUM(left_acl) == 0)
     493             :     {
     494           0 :         if (right_acl == NULL || ACL_NUM(right_acl) == 0)
     495           0 :             return NULL;
     496             :         else
     497           0 :             return aclcopy(right_acl);
     498             :     }
     499             :     else
     500             :     {
     501         192 :         if (right_acl == NULL || ACL_NUM(right_acl) == 0)
     502         138 :             return aclcopy(left_acl);
     503             :     }
     504             : 
     505             :     /* Merge them the hard way, one item at a time */
     506          54 :     result_acl = aclcopy(left_acl);
     507             : 
     508          54 :     aip = ACL_DAT(right_acl);
     509          54 :     num = ACL_NUM(right_acl);
     510             : 
     511         126 :     for (i = 0; i < num; i++, aip++)
     512             :     {
     513             :         Acl        *tmp_acl;
     514             : 
     515          72 :         tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
     516             :                             ownerId, DROP_RESTRICT);
     517          72 :         pfree(result_acl);
     518          72 :         result_acl = tmp_acl;
     519             :     }
     520             : 
     521          54 :     return result_acl;
     522             : }
     523             : 
     524             : /*
     525             :  * Sort the items in an ACL (into an arbitrary but consistent order)
     526             :  */
     527             : void
     528         764 : aclitemsort(Acl *acl)
     529             : {
     530         764 :     if (acl != NULL && ACL_NUM(acl) > 1)
     531         200 :         qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
     532         764 : }
     533             : 
     534             : /*
     535             :  * Check if two ACLs are exactly equal
     536             :  *
     537             :  * This will not detect equality if the two arrays contain the same items
     538             :  * in different orders.  To handle that case, sort both inputs first,
     539             :  * using aclitemsort().
     540             :  */
     541             : bool
     542         518 : aclequal(const Acl *left_acl, const Acl *right_acl)
     543             : {
     544             :     /* Check for cases where one or both are empty/null */
     545         518 :     if (left_acl == NULL || ACL_NUM(left_acl) == 0)
     546             :     {
     547           2 :         if (right_acl == NULL || ACL_NUM(right_acl) == 0)
     548           2 :             return true;
     549             :         else
     550           0 :             return false;
     551             :     }
     552             :     else
     553             :     {
     554         516 :         if (right_acl == NULL || ACL_NUM(right_acl) == 0)
     555          52 :             return false;
     556             :     }
     557             : 
     558         464 :     if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
     559         186 :         return false;
     560             : 
     561         278 :     if (memcmp(ACL_DAT(left_acl),
     562         278 :                ACL_DAT(right_acl),
     563         278 :                ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
     564         138 :         return true;
     565             : 
     566         140 :     return false;
     567             : }
     568             : 
     569             : /*
     570             :  * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
     571             :  */
     572             : static void
     573      147164 : check_acl(const Acl *acl)
     574             : {
     575      147164 :     if (ARR_ELEMTYPE(acl) != ACLITEMOID)
     576           0 :         ereport(ERROR,
     577             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     578             :                  errmsg("ACL array contains wrong data type")));
     579      147164 :     if (ARR_NDIM(acl) != 1)
     580           0 :         ereport(ERROR,
     581             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     582             :                  errmsg("ACL arrays must be one-dimensional")));
     583      147164 :     if (ARR_HASNULL(acl))
     584           0 :         ereport(ERROR,
     585             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     586             :                  errmsg("ACL arrays must not contain null values")));
     587      147164 : }
     588             : 
     589             : /*
     590             :  * aclitemin
     591             :  *      Allocates storage for, and fills in, a new AclItem given a string
     592             :  *      's' that contains an ACL specification.  See aclparse for details.
     593             :  *
     594             :  * RETURNS:
     595             :  *      the new AclItem
     596             :  */
     597             : Datum
     598         124 : aclitemin(PG_FUNCTION_ARGS)
     599             : {
     600         124 :     const char *s = PG_GETARG_CSTRING(0);
     601         124 :     Node       *escontext = fcinfo->context;
     602             :     AclItem    *aip;
     603             : 
     604         124 :     aip = (AclItem *) palloc(sizeof(AclItem));
     605             : 
     606         124 :     s = aclparse(s, aip, escontext);
     607         124 :     if (s == NULL)
     608          36 :         PG_RETURN_NULL();
     609             : 
     610          88 :     while (isspace((unsigned char) *s))
     611           0 :         ++s;
     612          88 :     if (*s)
     613           0 :         ereturn(escontext, (Datum) 0,
     614             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     615             :                  errmsg("extra garbage at the end of the ACL specification")));
     616             : 
     617          88 :     PG_RETURN_ACLITEM_P(aip);
     618             : }
     619             : 
     620             : /*
     621             :  * aclitemout
     622             :  *      Allocates storage for, and fills in, a new null-delimited string
     623             :  *      containing a formatted ACL specification.  See aclparse for details.
     624             :  *
     625             :  * RETURNS:
     626             :  *      the new string
     627             :  */
     628             : Datum
     629      696454 : aclitemout(PG_FUNCTION_ARGS)
     630             : {
     631      696454 :     AclItem    *aip = PG_GETARG_ACLITEM_P(0);
     632             :     char       *p;
     633             :     char       *out;
     634             :     HeapTuple   htup;
     635             :     unsigned    i;
     636             : 
     637      696454 :     out = palloc(strlen("=/") +
     638             :                  2 * N_ACL_RIGHTS +
     639             :                  2 * (2 * NAMEDATALEN + 2) +
     640             :                  1);
     641             : 
     642      696454 :     p = out;
     643      696454 :     *p = '\0';
     644             : 
     645      696454 :     if (aip->ai_grantee != ACL_ID_PUBLIC)
     646             :     {
     647      359580 :         htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
     648      359580 :         if (HeapTupleIsValid(htup))
     649             :         {
     650      359580 :             putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
     651      359580 :             ReleaseSysCache(htup);
     652             :         }
     653             :         else
     654             :         {
     655             :             /* Generate numeric OID if we don't find an entry */
     656           0 :             sprintf(p, "%u", aip->ai_grantee);
     657             :         }
     658             :     }
     659     3778822 :     while (*p)
     660     3082368 :         ++p;
     661             : 
     662      696454 :     *p++ = '=';
     663             : 
     664    11143264 :     for (i = 0; i < N_ACL_RIGHTS; ++i)
     665             :     {
     666    10446810 :         if (ACLITEM_GET_PRIVS(*aip) & (UINT64CONST(1) << i))
     667     1442628 :             *p++ = ACL_ALL_RIGHTS_STR[i];
     668    10446810 :         if (ACLITEM_GET_GOPTIONS(*aip) & (UINT64CONST(1) << i))
     669         330 :             *p++ = '*';
     670             :     }
     671             : 
     672      696454 :     *p++ = '/';
     673      696454 :     *p = '\0';
     674             : 
     675      696454 :     htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
     676      696454 :     if (HeapTupleIsValid(htup))
     677             :     {
     678      696454 :         putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
     679      696454 :         ReleaseSysCache(htup);
     680             :     }
     681             :     else
     682             :     {
     683             :         /* Generate numeric OID if we don't find an entry */
     684           0 :         sprintf(p, "%u", aip->ai_grantor);
     685             :     }
     686             : 
     687      696454 :     PG_RETURN_CSTRING(out);
     688             : }
     689             : 
     690             : /*
     691             :  * aclitem_match
     692             :  *      Two AclItems are considered to match iff they have the same
     693             :  *      grantee and grantor; the privileges are ignored.
     694             :  */
     695             : static bool
     696       17666 : aclitem_match(const AclItem *a1, const AclItem *a2)
     697             : {
     698       24484 :     return a1->ai_grantee == a2->ai_grantee &&
     699        6818 :         a1->ai_grantor == a2->ai_grantor;
     700             : }
     701             : 
     702             : /*
     703             :  * aclitemComparator
     704             :  *      qsort comparison function for AclItems
     705             :  */
     706             : static int
     707         218 : aclitemComparator(const void *arg1, const void *arg2)
     708             : {
     709         218 :     const AclItem *a1 = (const AclItem *) arg1;
     710         218 :     const AclItem *a2 = (const AclItem *) arg2;
     711             : 
     712         218 :     if (a1->ai_grantee > a2->ai_grantee)
     713          42 :         return 1;
     714         176 :     if (a1->ai_grantee < a2->ai_grantee)
     715         176 :         return -1;
     716           0 :     if (a1->ai_grantor > a2->ai_grantor)
     717           0 :         return 1;
     718           0 :     if (a1->ai_grantor < a2->ai_grantor)
     719           0 :         return -1;
     720           0 :     if (a1->ai_privs > a2->ai_privs)
     721           0 :         return 1;
     722           0 :     if (a1->ai_privs < a2->ai_privs)
     723           0 :         return -1;
     724           0 :     return 0;
     725             : }
     726             : 
     727             : /*
     728             :  * aclitem equality operator
     729             :  */
     730             : Datum
     731      116502 : aclitem_eq(PG_FUNCTION_ARGS)
     732             : {
     733      116502 :     AclItem    *a1 = PG_GETARG_ACLITEM_P(0);
     734      116502 :     AclItem    *a2 = PG_GETARG_ACLITEM_P(1);
     735             :     bool        result;
     736             : 
     737      334698 :     result = a1->ai_privs == a2->ai_privs &&
     738      216922 :         a1->ai_grantee == a2->ai_grantee &&
     739      100420 :         a1->ai_grantor == a2->ai_grantor;
     740      116502 :     PG_RETURN_BOOL(result);
     741             : }
     742             : 
     743             : /*
     744             :  * aclitem hash function
     745             :  *
     746             :  * We make aclitems hashable not so much because anyone is likely to hash
     747             :  * them, as because we want array equality to work on aclitem arrays, and
     748             :  * with the typcache mechanism we must have a hash or btree opclass.
     749             :  */
     750             : Datum
     751        1242 : hash_aclitem(PG_FUNCTION_ARGS)
     752             : {
     753        1242 :     AclItem    *a = PG_GETARG_ACLITEM_P(0);
     754             : 
     755             :     /* not very bright, but avoids any issue of padding in struct */
     756        1242 :     PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
     757             : }
     758             : 
     759             : /*
     760             :  * 64-bit hash function for aclitem.
     761             :  *
     762             :  * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
     763             :  */
     764             : Datum
     765          24 : hash_aclitem_extended(PG_FUNCTION_ARGS)
     766             : {
     767          24 :     AclItem    *a = PG_GETARG_ACLITEM_P(0);
     768          24 :     uint64      seed = PG_GETARG_INT64(1);
     769          24 :     uint32      sum = (uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor);
     770             : 
     771          24 :     return (seed == 0) ? UInt64GetDatum(sum) : hash_uint32_extended(sum, seed);
     772             : }
     773             : 
     774             : /*
     775             :  * acldefault()  --- create an ACL describing default access permissions
     776             :  *
     777             :  * Change this routine if you want to alter the default access policy for
     778             :  * newly-created objects (or any object with a NULL acl entry).  When
     779             :  * you make a change here, don't forget to update the GRANT man page,
     780             :  * which explains all the default permissions.
     781             :  *
     782             :  * Note that these are the hard-wired "defaults" that are used in the
     783             :  * absence of any pg_default_acl entry.
     784             :  */
     785             : Acl *
     786      386150 : acldefault(ObjectType objtype, Oid ownerId)
     787             : {
     788             :     AclMode     world_default;
     789             :     AclMode     owner_default;
     790             :     int         nacl;
     791             :     Acl        *acl;
     792             :     AclItem    *aip;
     793             : 
     794      386150 :     switch (objtype)
     795             :     {
     796       17488 :         case OBJECT_COLUMN:
     797             :             /* by default, columns have no extra privileges */
     798       17488 :             world_default = ACL_NO_RIGHTS;
     799       17488 :             owner_default = ACL_NO_RIGHTS;
     800       17488 :             break;
     801       98646 :         case OBJECT_TABLE:
     802       98646 :             world_default = ACL_NO_RIGHTS;
     803       98646 :             owner_default = ACL_ALL_RIGHTS_RELATION;
     804       98646 :             break;
     805        1150 :         case OBJECT_SEQUENCE:
     806        1150 :             world_default = ACL_NO_RIGHTS;
     807        1150 :             owner_default = ACL_ALL_RIGHTS_SEQUENCE;
     808        1150 :             break;
     809         930 :         case OBJECT_DATABASE:
     810             :             /* for backwards compatibility, grant some rights by default */
     811         930 :             world_default = ACL_CREATE_TEMP | ACL_CONNECT;
     812         930 :             owner_default = ACL_ALL_RIGHTS_DATABASE;
     813         930 :             break;
     814       47292 :         case OBJECT_FUNCTION:
     815             :             /* Grant EXECUTE by default, for now */
     816       47292 :             world_default = ACL_EXECUTE;
     817       47292 :             owner_default = ACL_ALL_RIGHTS_FUNCTION;
     818       47292 :             break;
     819         664 :         case OBJECT_LANGUAGE:
     820             :             /* Grant USAGE by default, for now */
     821         664 :             world_default = ACL_USAGE;
     822         664 :             owner_default = ACL_ALL_RIGHTS_LANGUAGE;
     823         664 :             break;
     824         246 :         case OBJECT_LARGEOBJECT:
     825         246 :             world_default = ACL_NO_RIGHTS;
     826         246 :             owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
     827         246 :             break;
     828        2898 :         case OBJECT_SCHEMA:
     829        2898 :             world_default = ACL_NO_RIGHTS;
     830        2898 :             owner_default = ACL_ALL_RIGHTS_SCHEMA;
     831        2898 :             break;
     832          28 :         case OBJECT_TABLESPACE:
     833          28 :             world_default = ACL_NO_RIGHTS;
     834          28 :             owner_default = ACL_ALL_RIGHTS_TABLESPACE;
     835          28 :             break;
     836         158 :         case OBJECT_FDW:
     837         158 :             world_default = ACL_NO_RIGHTS;
     838         158 :             owner_default = ACL_ALL_RIGHTS_FDW;
     839         158 :             break;
     840         274 :         case OBJECT_FOREIGN_SERVER:
     841         274 :             world_default = ACL_NO_RIGHTS;
     842         274 :             owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     843         274 :             break;
     844      216126 :         case OBJECT_DOMAIN:
     845             :         case OBJECT_TYPE:
     846      216126 :             world_default = ACL_USAGE;
     847      216126 :             owner_default = ACL_ALL_RIGHTS_TYPE;
     848      216126 :             break;
     849         250 :         case OBJECT_PARAMETER_ACL:
     850         250 :             world_default = ACL_NO_RIGHTS;
     851         250 :             owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
     852         250 :             break;
     853           0 :         default:
     854           0 :             elog(ERROR, "unrecognized object type: %d", (int) objtype);
     855             :             world_default = ACL_NO_RIGHTS;  /* keep compiler quiet */
     856             :             owner_default = ACL_NO_RIGHTS;
     857             :             break;
     858             :     }
     859             : 
     860      386150 :     nacl = 0;
     861      386150 :     if (world_default != ACL_NO_RIGHTS)
     862      265012 :         nacl++;
     863      386150 :     if (owner_default != ACL_NO_RIGHTS)
     864      368662 :         nacl++;
     865             : 
     866      386150 :     acl = allocacl(nacl);
     867      386150 :     aip = ACL_DAT(acl);
     868             : 
     869      386150 :     if (world_default != ACL_NO_RIGHTS)
     870             :     {
     871      265012 :         aip->ai_grantee = ACL_ID_PUBLIC;
     872      265012 :         aip->ai_grantor = ownerId;
     873      265012 :         ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
     874      265012 :         aip++;
     875             :     }
     876             : 
     877             :     /*
     878             :      * Note that the owner's entry shows all ordinary privileges but no grant
     879             :      * options.  This is because his grant options come "from the system" and
     880             :      * not from his own efforts.  (The SQL spec says that the owner's rights
     881             :      * come from a "_SYSTEM" authid.)  However, we do consider that the
     882             :      * owner's ordinary privileges are self-granted; this lets him revoke
     883             :      * them.  We implement the owner's grant options without any explicit
     884             :      * "_SYSTEM"-like ACL entry, by internally special-casing the owner
     885             :      * wherever we are testing grant options.
     886             :      */
     887      386150 :     if (owner_default != ACL_NO_RIGHTS)
     888             :     {
     889      368662 :         aip->ai_grantee = ownerId;
     890      368662 :         aip->ai_grantor = ownerId;
     891      368662 :         ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
     892             :     }
     893             : 
     894      386150 :     return acl;
     895             : }
     896             : 
     897             : 
     898             : /*
     899             :  * SQL-accessible version of acldefault().  Hackish mapping from "char" type to
     900             :  * OBJECT_* values.
     901             :  */
     902             : Datum
     903      310206 : acldefault_sql(PG_FUNCTION_ARGS)
     904             : {
     905      310206 :     char        objtypec = PG_GETARG_CHAR(0);
     906      310206 :     Oid         owner = PG_GETARG_OID(1);
     907      310206 :     ObjectType  objtype = 0;
     908             : 
     909      310206 :     switch (objtypec)
     910             :     {
     911           0 :         case 'c':
     912           0 :             objtype = OBJECT_COLUMN;
     913           0 :             break;
     914       85862 :         case 'r':
     915       85862 :             objtype = OBJECT_TABLE;
     916       85862 :             break;
     917        1018 :         case 's':
     918        1018 :             objtype = OBJECT_SEQUENCE;
     919        1018 :             break;
     920         120 :         case 'd':
     921         120 :             objtype = OBJECT_DATABASE;
     922         120 :             break;
     923        8052 :         case 'f':
     924        8052 :             objtype = OBJECT_FUNCTION;
     925        8052 :             break;
     926         388 :         case 'l':
     927         388 :             objtype = OBJECT_LANGUAGE;
     928         388 :             break;
     929         166 :         case 'L':
     930         166 :             objtype = OBJECT_LARGEOBJECT;
     931         166 :             break;
     932        2244 :         case 'n':
     933        2244 :             objtype = OBJECT_SCHEMA;
     934        2244 :             break;
     935          48 :         case 'p':
     936          48 :             objtype = OBJECT_PARAMETER_ACL;
     937          48 :             break;
     938          10 :         case 't':
     939          10 :             objtype = OBJECT_TABLESPACE;
     940          10 :             break;
     941         132 :         case 'F':
     942         132 :             objtype = OBJECT_FDW;
     943         132 :             break;
     944         136 :         case 'S':
     945         136 :             objtype = OBJECT_FOREIGN_SERVER;
     946         136 :             break;
     947      212030 :         case 'T':
     948      212030 :             objtype = OBJECT_TYPE;
     949      212030 :             break;
     950           0 :         default:
     951           0 :             elog(ERROR, "unrecognized object type abbreviation: %c", objtypec);
     952             :     }
     953             : 
     954      310206 :     PG_RETURN_ACL_P(acldefault(objtype, owner));
     955             : }
     956             : 
     957             : 
     958             : /*
     959             :  * Update an ACL array to add or remove specified privileges.
     960             :  *
     961             :  *  old_acl: the input ACL array
     962             :  *  mod_aip: defines the privileges to be added, removed, or substituted
     963             :  *  modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
     964             :  *  ownerId: Oid of object owner
     965             :  *  behavior: RESTRICT or CASCADE behavior for recursive removal
     966             :  *
     967             :  * ownerid and behavior are only relevant when the update operation specifies
     968             :  * deletion of grant options.
     969             :  *
     970             :  * The result is a modified copy; the input object is not changed.
     971             :  *
     972             :  * NB: caller is responsible for having detoasted the input ACL, if needed.
     973             :  */
     974             : Acl *
     975       33540 : aclupdate(const Acl *old_acl, const AclItem *mod_aip,
     976             :           int modechg, Oid ownerId, DropBehavior behavior)
     977             : {
     978       33540 :     Acl        *new_acl = NULL;
     979             :     AclItem    *old_aip,
     980       33540 :                *new_aip = NULL;
     981             :     AclMode     old_rights,
     982             :                 old_goptions,
     983             :                 new_rights,
     984             :                 new_goptions;
     985             :     int         dst,
     986             :                 num;
     987             : 
     988             :     /* Caller probably already checked old_acl, but be safe */
     989       33540 :     check_acl(old_acl);
     990             : 
     991             :     /* If granting grant options, check for circularity */
     992       33540 :     if (modechg != ACL_MODECHG_DEL &&
     993       10148 :         ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
     994          86 :         check_circularity(old_acl, mod_aip, ownerId);
     995             : 
     996       33540 :     num = ACL_NUM(old_acl);
     997       33540 :     old_aip = ACL_DAT(old_acl);
     998             : 
     999             :     /*
    1000             :      * Search the ACL for an existing entry for this grantee and grantor. If
    1001             :      * one exists, just modify the entry in-place (well, in the same position,
    1002             :      * since we actually return a copy); otherwise, insert the new entry at
    1003             :      * the end.
    1004             :      */
    1005             : 
    1006       44412 :     for (dst = 0; dst < num; ++dst)
    1007             :     {
    1008       17658 :         if (aclitem_match(mod_aip, old_aip + dst))
    1009             :         {
    1010             :             /* found a match, so modify existing item */
    1011        6786 :             new_acl = allocacl(num);
    1012        6786 :             new_aip = ACL_DAT(new_acl);
    1013        6786 :             memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
    1014        6786 :             break;
    1015             :         }
    1016             :     }
    1017             : 
    1018       33540 :     if (dst == num)
    1019             :     {
    1020             :         /* need to append a new item */
    1021       26754 :         new_acl = allocacl(num + 1);
    1022       26754 :         new_aip = ACL_DAT(new_acl);
    1023       26754 :         memcpy(new_aip, old_aip, num * sizeof(AclItem));
    1024             : 
    1025             :         /* initialize the new entry with no permissions */
    1026       26754 :         new_aip[dst].ai_grantee = mod_aip->ai_grantee;
    1027       26754 :         new_aip[dst].ai_grantor = mod_aip->ai_grantor;
    1028       26754 :         ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
    1029             :                                    ACL_NO_RIGHTS, ACL_NO_RIGHTS);
    1030       26754 :         num++;                  /* set num to the size of new_acl */
    1031             :     }
    1032             : 
    1033       33540 :     old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
    1034       33540 :     old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
    1035             : 
    1036             :     /* apply the specified permissions change */
    1037       33540 :     switch (modechg)
    1038             :     {
    1039       10148 :         case ACL_MODECHG_ADD:
    1040       10148 :             ACLITEM_SET_RIGHTS(new_aip[dst],
    1041             :                                old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
    1042       10148 :             break;
    1043       23392 :         case ACL_MODECHG_DEL:
    1044       23392 :             ACLITEM_SET_RIGHTS(new_aip[dst],
    1045             :                                old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
    1046       23392 :             break;
    1047           0 :         case ACL_MODECHG_EQL:
    1048           0 :             ACLITEM_SET_RIGHTS(new_aip[dst],
    1049             :                                ACLITEM_GET_RIGHTS(*mod_aip));
    1050           0 :             break;
    1051             :     }
    1052             : 
    1053       33540 :     new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
    1054       33540 :     new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
    1055             : 
    1056             :     /*
    1057             :      * If the adjusted entry has no permissions, delete it from the list.
    1058             :      */
    1059       33540 :     if (new_rights == ACL_NO_RIGHTS)
    1060             :     {
    1061       23142 :         memmove(new_aip + dst,
    1062       23142 :                 new_aip + dst + 1,
    1063       23142 :                 (num - dst - 1) * sizeof(AclItem));
    1064             :         /* Adjust array size to be 'num - 1' items */
    1065       23142 :         ARR_DIMS(new_acl)[0] = num - 1;
    1066       23142 :         SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
    1067             :     }
    1068             : 
    1069             :     /*
    1070             :      * Remove abandoned privileges (cascading revoke).  Currently we can only
    1071             :      * handle this when the grantee is not PUBLIC.
    1072             :      */
    1073       33540 :     if ((old_goptions & ~new_goptions) != 0)
    1074             :     {
    1075             :         Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
    1076          90 :         new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
    1077          90 :                                    (old_goptions & ~new_goptions),
    1078             :                                    ownerId, behavior);
    1079             :     }
    1080             : 
    1081       33528 :     return new_acl;
    1082             : }
    1083             : 
    1084             : /*
    1085             :  * Update an ACL array to reflect a change of owner to the parent object
    1086             :  *
    1087             :  *  old_acl: the input ACL array (must not be NULL)
    1088             :  *  oldOwnerId: Oid of the old object owner
    1089             :  *  newOwnerId: Oid of the new object owner
    1090             :  *
    1091             :  * The result is a modified copy; the input object is not changed.
    1092             :  *
    1093             :  * NB: caller is responsible for having detoasted the input ACL, if needed.
    1094             :  */
    1095             : Acl *
    1096          56 : aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
    1097             : {
    1098             :     Acl        *new_acl;
    1099             :     AclItem    *new_aip;
    1100             :     AclItem    *old_aip;
    1101             :     AclItem    *dst_aip;
    1102             :     AclItem    *src_aip;
    1103             :     AclItem    *targ_aip;
    1104          56 :     bool        newpresent = false;
    1105             :     int         dst,
    1106             :                 src,
    1107             :                 targ,
    1108             :                 num;
    1109             : 
    1110          56 :     check_acl(old_acl);
    1111             : 
    1112             :     /*
    1113             :      * Make a copy of the given ACL, substituting new owner ID for old
    1114             :      * wherever it appears as either grantor or grantee.  Also note if the new
    1115             :      * owner ID is already present.
    1116             :      */
    1117          56 :     num = ACL_NUM(old_acl);
    1118          56 :     old_aip = ACL_DAT(old_acl);
    1119          56 :     new_acl = allocacl(num);
    1120          56 :     new_aip = ACL_DAT(new_acl);
    1121          56 :     memcpy(new_aip, old_aip, num * sizeof(AclItem));
    1122         136 :     for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
    1123             :     {
    1124          80 :         if (dst_aip->ai_grantor == oldOwnerId)
    1125          80 :             dst_aip->ai_grantor = newOwnerId;
    1126           0 :         else if (dst_aip->ai_grantor == newOwnerId)
    1127           0 :             newpresent = true;
    1128          80 :         if (dst_aip->ai_grantee == oldOwnerId)
    1129          56 :             dst_aip->ai_grantee = newOwnerId;
    1130          24 :         else if (dst_aip->ai_grantee == newOwnerId)
    1131           8 :             newpresent = true;
    1132             :     }
    1133             : 
    1134             :     /*
    1135             :      * If the old ACL contained any references to the new owner, then we may
    1136             :      * now have generated an ACL containing duplicate entries.  Find them and
    1137             :      * merge them so that there are not duplicates.  (This is relatively
    1138             :      * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
    1139             :      * be the normal case.)
    1140             :      *
    1141             :      * To simplify deletion of duplicate entries, we temporarily leave them in
    1142             :      * the array but set their privilege masks to zero; when we reach such an
    1143             :      * entry it's just skipped.  (Thus, a side effect of this code will be to
    1144             :      * remove privilege-free entries, should there be any in the input.)  dst
    1145             :      * is the next output slot, targ is the currently considered input slot
    1146             :      * (always >= dst), and src scans entries to the right of targ looking for
    1147             :      * duplicates.  Once an entry has been emitted to dst it is known
    1148             :      * duplicate-free and need not be considered anymore.
    1149             :      */
    1150          56 :     if (newpresent)
    1151             :     {
    1152           8 :         dst = 0;
    1153          24 :         for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
    1154             :         {
    1155             :             /* ignore if deleted in an earlier pass */
    1156          16 :             if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
    1157           8 :                 continue;
    1158             :             /* find and merge any duplicates */
    1159          16 :             for (src = targ + 1, src_aip = targ_aip + 1; src < num;
    1160           8 :                  src++, src_aip++)
    1161             :             {
    1162           8 :                 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
    1163           0 :                     continue;
    1164           8 :                 if (aclitem_match(targ_aip, src_aip))
    1165             :                 {
    1166           8 :                     ACLITEM_SET_RIGHTS(*targ_aip,
    1167             :                                        ACLITEM_GET_RIGHTS(*targ_aip) |
    1168             :                                        ACLITEM_GET_RIGHTS(*src_aip));
    1169             :                     /* mark the duplicate deleted */
    1170           8 :                     ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
    1171             :                 }
    1172             :             }
    1173             :             /* and emit to output */
    1174           8 :             new_aip[dst] = *targ_aip;
    1175           8 :             dst++;
    1176             :         }
    1177             :         /* Adjust array size to be 'dst' items */
    1178           8 :         ARR_DIMS(new_acl)[0] = dst;
    1179           8 :         SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
    1180             :     }
    1181             : 
    1182          56 :     return new_acl;
    1183             : }
    1184             : 
    1185             : 
    1186             : /*
    1187             :  * When granting grant options, we must disallow attempts to set up circular
    1188             :  * chains of grant options.  Suppose A (the object owner) grants B some
    1189             :  * privileges with grant option, and B re-grants them to C.  If C could
    1190             :  * grant the privileges to B as well, then A would be unable to effectively
    1191             :  * revoke the privileges from B, since recursive_revoke would consider that
    1192             :  * B still has 'em from C.
    1193             :  *
    1194             :  * We check for this by recursively deleting all grant options belonging to
    1195             :  * the target grantee, and then seeing if the would-be grantor still has the
    1196             :  * grant option or not.
    1197             :  */
    1198             : static void
    1199          86 : check_circularity(const Acl *old_acl, const AclItem *mod_aip,
    1200             :                   Oid ownerId)
    1201             : {
    1202             :     Acl        *acl;
    1203             :     AclItem    *aip;
    1204             :     int         i,
    1205             :                 num;
    1206             :     AclMode     own_privs;
    1207             : 
    1208          86 :     check_acl(old_acl);
    1209             : 
    1210             :     /*
    1211             :      * For now, grant options can only be granted to roles, not PUBLIC.
    1212             :      * Otherwise we'd have to work a bit harder here.
    1213             :      */
    1214             :     Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
    1215             : 
    1216             :     /* The owner always has grant options, no need to check */
    1217          86 :     if (mod_aip->ai_grantor == ownerId)
    1218          68 :         return;
    1219             : 
    1220             :     /* Make a working copy */
    1221          18 :     acl = allocacl(ACL_NUM(old_acl));
    1222          18 :     memcpy(acl, old_acl, ACL_SIZE(old_acl));
    1223             : 
    1224             :     /* Zap all grant options of target grantee, plus what depends on 'em */
    1225          24 : cc_restart:
    1226          24 :     num = ACL_NUM(acl);
    1227          24 :     aip = ACL_DAT(acl);
    1228          96 :     for (i = 0; i < num; i++)
    1229             :     {
    1230          78 :         if (aip[i].ai_grantee == mod_aip->ai_grantee &&
    1231           6 :             ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
    1232             :         {
    1233             :             Acl        *new_acl;
    1234             : 
    1235             :             /* We'll actually zap ordinary privs too, but no matter */
    1236           6 :             new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
    1237             :                                 ownerId, DROP_CASCADE);
    1238             : 
    1239           6 :             pfree(acl);
    1240           6 :             acl = new_acl;
    1241             : 
    1242           6 :             goto cc_restart;
    1243             :         }
    1244             :     }
    1245             : 
    1246             :     /* Now we can compute grantor's independently-derived privileges */
    1247          18 :     own_privs = aclmask(acl,
    1248             :                         mod_aip->ai_grantor,
    1249             :                         ownerId,
    1250          18 :                         ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
    1251             :                         ACLMASK_ALL);
    1252          18 :     own_privs = ACL_OPTION_TO_PRIVS(own_privs);
    1253             : 
    1254          18 :     if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
    1255           0 :         ereport(ERROR,
    1256             :                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1257             :                  errmsg("grant options cannot be granted back to your own grantor")));
    1258             : 
    1259          18 :     pfree(acl);
    1260             : }
    1261             : 
    1262             : 
    1263             : /*
    1264             :  * Ensure that no privilege is "abandoned".  A privilege is abandoned
    1265             :  * if the user that granted the privilege loses the grant option.  (So
    1266             :  * the chain through which it was granted is broken.)  Either the
    1267             :  * abandoned privileges are revoked as well, or an error message is
    1268             :  * printed, depending on the drop behavior option.
    1269             :  *
    1270             :  *  acl: the input ACL list
    1271             :  *  grantee: the user from whom some grant options have been revoked
    1272             :  *  revoke_privs: the grant options being revoked
    1273             :  *  ownerId: Oid of object owner
    1274             :  *  behavior: RESTRICT or CASCADE behavior for recursive removal
    1275             :  *
    1276             :  * The input Acl object is pfree'd if replaced.
    1277             :  */
    1278             : static Acl *
    1279          90 : recursive_revoke(Acl *acl,
    1280             :                  Oid grantee,
    1281             :                  AclMode revoke_privs,
    1282             :                  Oid ownerId,
    1283             :                  DropBehavior behavior)
    1284             : {
    1285             :     AclMode     still_has;
    1286             :     AclItem    *aip;
    1287             :     int         i,
    1288             :                 num;
    1289             : 
    1290          90 :     check_acl(acl);
    1291             : 
    1292             :     /* The owner can never truly lose grant options, so short-circuit */
    1293          90 :     if (grantee == ownerId)
    1294           0 :         return acl;
    1295             : 
    1296             :     /* The grantee might still have some grant options via another grantor */
    1297          90 :     still_has = aclmask(acl, grantee, ownerId,
    1298             :                         ACL_GRANT_OPTION_FOR(revoke_privs),
    1299             :                         ACLMASK_ALL);
    1300          90 :     revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
    1301          90 :     if (revoke_privs == ACL_NO_RIGHTS)
    1302           6 :         return acl;
    1303             : 
    1304          84 : restart:
    1305         120 :     num = ACL_NUM(acl);
    1306         120 :     aip = ACL_DAT(acl);
    1307         388 :     for (i = 0; i < num; i++)
    1308             :     {
    1309         316 :         if (aip[i].ai_grantor == grantee
    1310          48 :             && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
    1311             :         {
    1312             :             AclItem     mod_acl;
    1313             :             Acl        *new_acl;
    1314             : 
    1315          48 :             if (behavior == DROP_RESTRICT)
    1316          12 :                 ereport(ERROR,
    1317             :                         (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
    1318             :                          errmsg("dependent privileges exist"),
    1319             :                          errhint("Use CASCADE to revoke them too.")));
    1320             : 
    1321          36 :             mod_acl.ai_grantor = grantee;
    1322          36 :             mod_acl.ai_grantee = aip[i].ai_grantee;
    1323          36 :             ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
    1324             :                                        revoke_privs,
    1325             :                                        revoke_privs);
    1326             : 
    1327          36 :             new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
    1328             :                                 ownerId, behavior);
    1329             : 
    1330          36 :             pfree(acl);
    1331          36 :             acl = new_acl;
    1332             : 
    1333          36 :             goto restart;
    1334             :         }
    1335             :     }
    1336             : 
    1337          72 :     return acl;
    1338             : }
    1339             : 
    1340             : 
    1341             : /*
    1342             :  * aclmask --- compute bitmask of all privileges held by roleid.
    1343             :  *
    1344             :  * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
    1345             :  * held by the given roleid according to the given ACL list, ANDed
    1346             :  * with 'mask'.  (The point of passing 'mask' is to let the routine
    1347             :  * exit early if all privileges of interest have been found.)
    1348             :  *
    1349             :  * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
    1350             :  * is known true.  (This lets us exit soonest in cases where the
    1351             :  * caller is only going to test for zero or nonzero result.)
    1352             :  *
    1353             :  * Usage patterns:
    1354             :  *
    1355             :  * To see if any of a set of privileges are held:
    1356             :  *      if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
    1357             :  *
    1358             :  * To see if all of a set of privileges are held:
    1359             :  *      if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
    1360             :  *
    1361             :  * To determine exactly which of a set of privileges are held:
    1362             :  *      heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
    1363             :  */
    1364             : AclMode
    1365       92554 : aclmask(const Acl *acl, Oid roleid, Oid ownerId,
    1366             :         AclMode mask, AclMaskHow how)
    1367             : {
    1368             :     AclMode     result;
    1369             :     AclMode     remaining;
    1370             :     AclItem    *aidat;
    1371             :     int         i,
    1372             :                 num;
    1373             : 
    1374             :     /*
    1375             :      * Null ACL should not happen, since caller should have inserted
    1376             :      * appropriate default
    1377             :      */
    1378       92554 :     if (acl == NULL)
    1379           0 :         elog(ERROR, "null ACL");
    1380             : 
    1381       92554 :     check_acl(acl);
    1382             : 
    1383             :     /* Quick exit for mask == 0 */
    1384       92554 :     if (mask == 0)
    1385          70 :         return 0;
    1386             : 
    1387       92484 :     result = 0;
    1388             : 
    1389             :     /* Owner always implicitly has all grant options */
    1390       92666 :     if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
    1391         182 :         has_privs_of_role(roleid, ownerId))
    1392             :     {
    1393           6 :         result = mask & ACLITEM_ALL_GOPTION_BITS;
    1394           6 :         if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
    1395           6 :             return result;
    1396             :     }
    1397             : 
    1398       92478 :     num = ACL_NUM(acl);
    1399       92478 :     aidat = ACL_DAT(acl);
    1400             : 
    1401             :     /*
    1402             :      * Check privileges granted directly to roleid or to public
    1403             :      */
    1404      122984 :     for (i = 0; i < num; i++)
    1405             :     {
    1406      117878 :         AclItem    *aidata = &aidat[i];
    1407             : 
    1408      117878 :         if (aidata->ai_grantee == ACL_ID_PUBLIC ||
    1409       43080 :             aidata->ai_grantee == roleid)
    1410             :         {
    1411       89190 :             result |= aidata->ai_privs & mask;
    1412       89190 :             if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
    1413       87372 :                 return result;
    1414             :         }
    1415             :     }
    1416             : 
    1417             :     /*
    1418             :      * Check privileges granted indirectly via role memberships. We do this in
    1419             :      * a separate pass to minimize expensive indirect membership tests.  In
    1420             :      * particular, it's worth testing whether a given ACL entry grants any
    1421             :      * privileges still of interest before we perform the has_privs_of_role
    1422             :      * test.
    1423             :      */
    1424        5106 :     remaining = mask & ~result;
    1425       13160 :     for (i = 0; i < num; i++)
    1426             :     {
    1427        8184 :         AclItem    *aidata = &aidat[i];
    1428             : 
    1429        8184 :         if (aidata->ai_grantee == ACL_ID_PUBLIC ||
    1430        8098 :             aidata->ai_grantee == roleid)
    1431        1694 :             continue;           /* already checked it */
    1432             : 
    1433       12062 :         if ((aidata->ai_privs & remaining) &&
    1434        5572 :             has_privs_of_role(roleid, aidata->ai_grantee))
    1435             :         {
    1436         130 :             result |= aidata->ai_privs & mask;
    1437         130 :             if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
    1438         130 :                 return result;
    1439           0 :             remaining = mask & ~result;
    1440             :         }
    1441             :     }
    1442             : 
    1443        4976 :     return result;
    1444             : }
    1445             : 
    1446             : 
    1447             : /*
    1448             :  * aclmask_direct --- compute bitmask of all privileges held by roleid.
    1449             :  *
    1450             :  * This is exactly like aclmask() except that we consider only privileges
    1451             :  * held *directly* by roleid, not those inherited via role membership.
    1452             :  */
    1453             : static AclMode
    1454         234 : aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
    1455             :                AclMode mask, AclMaskHow how)
    1456             : {
    1457             :     AclMode     result;
    1458             :     AclItem    *aidat;
    1459             :     int         i,
    1460             :                 num;
    1461             : 
    1462             :     /*
    1463             :      * Null ACL should not happen, since caller should have inserted
    1464             :      * appropriate default
    1465             :      */
    1466         234 :     if (acl == NULL)
    1467           0 :         elog(ERROR, "null ACL");
    1468             : 
    1469         234 :     check_acl(acl);
    1470             : 
    1471             :     /* Quick exit for mask == 0 */
    1472         234 :     if (mask == 0)
    1473           0 :         return 0;
    1474             : 
    1475         234 :     result = 0;
    1476             : 
    1477             :     /* Owner always implicitly has all grant options */
    1478         234 :     if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
    1479             :         roleid == ownerId)
    1480             :     {
    1481           0 :         result = mask & ACLITEM_ALL_GOPTION_BITS;
    1482           0 :         if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
    1483           0 :             return result;
    1484             :     }
    1485             : 
    1486         234 :     num = ACL_NUM(acl);
    1487         234 :     aidat = ACL_DAT(acl);
    1488             : 
    1489             :     /*
    1490             :      * Check privileges granted directly to roleid (and not to public)
    1491             :      */
    1492         684 :     for (i = 0; i < num; i++)
    1493             :     {
    1494         606 :         AclItem    *aidata = &aidat[i];
    1495             : 
    1496         606 :         if (aidata->ai_grantee == roleid)
    1497             :         {
    1498         192 :             result |= aidata->ai_privs & mask;
    1499         192 :             if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
    1500         156 :                 return result;
    1501             :         }
    1502             :     }
    1503             : 
    1504          78 :     return result;
    1505             : }
    1506             : 
    1507             : 
    1508             : /*
    1509             :  * aclmembers
    1510             :  *      Find out all the roleids mentioned in an Acl.
    1511             :  *      Note that we do not distinguish grantors from grantees.
    1512             :  *
    1513             :  * *roleids is set to point to a palloc'd array containing distinct OIDs
    1514             :  * in sorted order.  The length of the array is the function result.
    1515             :  */
    1516             : int
    1517       36666 : aclmembers(const Acl *acl, Oid **roleids)
    1518             : {
    1519             :     Oid        *list;
    1520             :     const AclItem *acldat;
    1521             :     int         i,
    1522             :                 j;
    1523             : 
    1524       36666 :     if (acl == NULL || ACL_NUM(acl) == 0)
    1525             :     {
    1526       16110 :         *roleids = NULL;
    1527       16110 :         return 0;
    1528             :     }
    1529             : 
    1530       20556 :     check_acl(acl);
    1531             : 
    1532             :     /* Allocate the worst-case space requirement */
    1533       20556 :     list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
    1534       20556 :     acldat = ACL_DAT(acl);
    1535             : 
    1536             :     /*
    1537             :      * Walk the ACL collecting mentioned RoleIds.
    1538             :      */
    1539       20556 :     j = 0;
    1540       51918 :     for (i = 0; i < ACL_NUM(acl); i++)
    1541             :     {
    1542       31362 :         const AclItem *ai = &acldat[i];
    1543             : 
    1544       31362 :         if (ai->ai_grantee != ACL_ID_PUBLIC)
    1545       23884 :             list[j++] = ai->ai_grantee;
    1546             :         /* grantor is currently never PUBLIC, but let's check anyway */
    1547       31362 :         if (ai->ai_grantor != ACL_ID_PUBLIC)
    1548       31362 :             list[j++] = ai->ai_grantor;
    1549             :     }
    1550             : 
    1551             :     /* Sort the array */
    1552       20556 :     qsort(list, j, sizeof(Oid), oid_cmp);
    1553             : 
    1554             :     /*
    1555             :      * We could repalloc the array down to minimum size, but it's hardly worth
    1556             :      * it since it's only transient memory.
    1557             :      */
    1558       20556 :     *roleids = list;
    1559             : 
    1560             :     /* Remove duplicates from the array */
    1561       20556 :     return qunique(list, j, sizeof(Oid), oid_cmp);
    1562             : }
    1563             : 
    1564             : 
    1565             : /*
    1566             :  * aclinsert (exported function)
    1567             :  */
    1568             : Datum
    1569           0 : aclinsert(PG_FUNCTION_ARGS)
    1570             : {
    1571           0 :     ereport(ERROR,
    1572             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1573             :              errmsg("aclinsert is no longer supported")));
    1574             : 
    1575             :     PG_RETURN_NULL();           /* keep compiler quiet */
    1576             : }
    1577             : 
    1578             : Datum
    1579           0 : aclremove(PG_FUNCTION_ARGS)
    1580             : {
    1581           0 :     ereport(ERROR,
    1582             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1583             :              errmsg("aclremove is no longer supported")));
    1584             : 
    1585             :     PG_RETURN_NULL();           /* keep compiler quiet */
    1586             : }
    1587             : 
    1588             : Datum
    1589           0 : aclcontains(PG_FUNCTION_ARGS)
    1590             : {
    1591           0 :     Acl        *acl = PG_GETARG_ACL_P(0);
    1592           0 :     AclItem    *aip = PG_GETARG_ACLITEM_P(1);
    1593             :     AclItem    *aidat;
    1594             :     int         i,
    1595             :                 num;
    1596             : 
    1597           0 :     check_acl(acl);
    1598           0 :     num = ACL_NUM(acl);
    1599           0 :     aidat = ACL_DAT(acl);
    1600           0 :     for (i = 0; i < num; ++i)
    1601             :     {
    1602           0 :         if (aip->ai_grantee == aidat[i].ai_grantee &&
    1603           0 :             aip->ai_grantor == aidat[i].ai_grantor &&
    1604           0 :             (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
    1605           0 :             PG_RETURN_BOOL(true);
    1606             :     }
    1607           0 :     PG_RETURN_BOOL(false);
    1608             : }
    1609             : 
    1610             : Datum
    1611          18 : makeaclitem(PG_FUNCTION_ARGS)
    1612             : {
    1613          18 :     Oid         grantee = PG_GETARG_OID(0);
    1614          18 :     Oid         grantor = PG_GETARG_OID(1);
    1615          18 :     text       *privtext = PG_GETARG_TEXT_PP(2);
    1616          18 :     bool        goption = PG_GETARG_BOOL(3);
    1617             :     AclItem    *result;
    1618             :     AclMode     priv;
    1619             :     static const priv_map any_priv_map[] = {
    1620             :         {"SELECT", ACL_SELECT},
    1621             :         {"INSERT", ACL_INSERT},
    1622             :         {"UPDATE", ACL_UPDATE},
    1623             :         {"DELETE", ACL_DELETE},
    1624             :         {"TRUNCATE", ACL_TRUNCATE},
    1625             :         {"REFERENCES", ACL_REFERENCES},
    1626             :         {"TRIGGER", ACL_TRIGGER},
    1627             :         {"EXECUTE", ACL_EXECUTE},
    1628             :         {"USAGE", ACL_USAGE},
    1629             :         {"CREATE", ACL_CREATE},
    1630             :         {"TEMP", ACL_CREATE_TEMP},
    1631             :         {"TEMPORARY", ACL_CREATE_TEMP},
    1632             :         {"CONNECT", ACL_CONNECT},
    1633             :         {"SET", ACL_SET},
    1634             :         {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
    1635             :         {"MAINTAIN", ACL_MAINTAIN},
    1636             :         {"RULE", 0},          /* ignore old RULE privileges */
    1637             :         {NULL, 0}
    1638             :     };
    1639             : 
    1640          18 :     priv = convert_any_priv_string(privtext, any_priv_map);
    1641             : 
    1642          12 :     result = (AclItem *) palloc(sizeof(AclItem));
    1643             : 
    1644          12 :     result->ai_grantee = grantee;
    1645          12 :     result->ai_grantor = grantor;
    1646             : 
    1647          12 :     ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
    1648             :                                (goption ? priv : ACL_NO_RIGHTS));
    1649             : 
    1650          12 :     PG_RETURN_ACLITEM_P(result);
    1651             : }
    1652             : 
    1653             : 
    1654             : /*
    1655             :  * convert_any_priv_string: recognize privilege strings for has_foo_privilege
    1656             :  *
    1657             :  * We accept a comma-separated list of case-insensitive privilege names,
    1658             :  * producing a bitmask of the OR'd privilege bits.  We are liberal about
    1659             :  * whitespace between items, not so much about whitespace within items.
    1660             :  * The allowed privilege names are given as an array of priv_map structs,
    1661             :  * terminated by one with a NULL name pointer.
    1662             :  */
    1663             : static AclMode
    1664       95480 : convert_any_priv_string(text *priv_type_text,
    1665             :                         const priv_map *privileges)
    1666             : {
    1667       95480 :     AclMode     result = 0;
    1668       95480 :     char       *priv_type = text_to_cstring(priv_type_text);
    1669             :     char       *chunk;
    1670             :     char       *next_chunk;
    1671             : 
    1672             :     /* We rely on priv_type being a private, modifiable string */
    1673      191080 :     for (chunk = priv_type; chunk; chunk = next_chunk)
    1674             :     {
    1675             :         int         chunk_len;
    1676             :         const priv_map *this_priv;
    1677             : 
    1678             :         /* Split string at commas */
    1679       95632 :         next_chunk = strchr(chunk, ',');
    1680       95632 :         if (next_chunk)
    1681         156 :             *next_chunk++ = '\0';
    1682             : 
    1683             :         /* Drop leading/trailing whitespace in this chunk */
    1684       95676 :         while (*chunk && isspace((unsigned char) *chunk))
    1685          44 :             chunk++;
    1686       95632 :         chunk_len = strlen(chunk);
    1687       95650 :         while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
    1688          18 :             chunk_len--;
    1689       95632 :         chunk[chunk_len] = '\0';
    1690             : 
    1691             :         /* Match to the privileges list */
    1692       97612 :         for (this_priv = privileges; this_priv->name; this_priv++)
    1693             :         {
    1694       97580 :             if (pg_strcasecmp(this_priv->name, chunk) == 0)
    1695             :             {
    1696       95600 :                 result |= this_priv->value;
    1697       95600 :                 break;
    1698             :             }
    1699             :         }
    1700       95632 :         if (!this_priv->name)
    1701          32 :             ereport(ERROR,
    1702             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1703             :                      errmsg("unrecognized privilege type: \"%s\"", chunk)));
    1704             :     }
    1705             : 
    1706       95448 :     pfree(priv_type);
    1707       95448 :     return result;
    1708             : }
    1709             : 
    1710             : 
    1711             : static const char *
    1712          96 : convert_aclright_to_string(int aclright)
    1713             : {
    1714          96 :     switch (aclright)
    1715             :     {
    1716           0 :         case ACL_INSERT:
    1717           0 :             return "INSERT";
    1718           0 :         case ACL_SELECT:
    1719           0 :             return "SELECT";
    1720           0 :         case ACL_UPDATE:
    1721           0 :             return "UPDATE";
    1722           0 :         case ACL_DELETE:
    1723           0 :             return "DELETE";
    1724           0 :         case ACL_TRUNCATE:
    1725           0 :             return "TRUNCATE";
    1726           0 :         case ACL_REFERENCES:
    1727           0 :             return "REFERENCES";
    1728           0 :         case ACL_TRIGGER:
    1729           0 :             return "TRIGGER";
    1730           0 :         case ACL_EXECUTE:
    1731           0 :             return "EXECUTE";
    1732          96 :         case ACL_USAGE:
    1733          96 :             return "USAGE";
    1734           0 :         case ACL_CREATE:
    1735           0 :             return "CREATE";
    1736           0 :         case ACL_CREATE_TEMP:
    1737           0 :             return "TEMPORARY";
    1738           0 :         case ACL_CONNECT:
    1739           0 :             return "CONNECT";
    1740           0 :         case ACL_SET:
    1741           0 :             return "SET";
    1742           0 :         case ACL_ALTER_SYSTEM:
    1743           0 :             return "ALTER SYSTEM";
    1744           0 :         case ACL_MAINTAIN:
    1745           0 :             return "MAINTAIN";
    1746           0 :         default:
    1747           0 :             elog(ERROR, "unrecognized aclright: %d", aclright);
    1748             :             return NULL;
    1749             :     }
    1750             : }
    1751             : 
    1752             : 
    1753             : /*----------
    1754             :  * Convert an aclitem[] to a table.
    1755             :  *
    1756             :  * Example:
    1757             :  *
    1758             :  * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
    1759             :  *
    1760             :  * returns the table
    1761             :  *
    1762             :  * {{ OID(joe), 0::OID,   'SELECT', false },
    1763             :  *  { OID(joe), OID(foo), 'INSERT', true },
    1764             :  *  { OID(joe), OID(foo), 'UPDATE', false }}
    1765             :  *----------
    1766             :  */
    1767             : Datum
    1768         144 : aclexplode(PG_FUNCTION_ARGS)
    1769             : {
    1770         144 :     Acl        *acl = PG_GETARG_ACL_P(0);
    1771             :     FuncCallContext *funcctx;
    1772             :     int        *idx;
    1773             :     AclItem    *aidat;
    1774             : 
    1775         144 :     if (SRF_IS_FIRSTCALL())
    1776             :     {
    1777             :         TupleDesc   tupdesc;
    1778             :         MemoryContext oldcontext;
    1779             : 
    1780          48 :         check_acl(acl);
    1781             : 
    1782          48 :         funcctx = SRF_FIRSTCALL_INIT();
    1783          48 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    1784             : 
    1785             :         /*
    1786             :          * build tupdesc for result tuples (matches out parameters in pg_proc
    1787             :          * entry)
    1788             :          */
    1789          48 :         tupdesc = CreateTemplateTupleDesc(4);
    1790          48 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
    1791             :                            OIDOID, -1, 0);
    1792          48 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
    1793             :                            OIDOID, -1, 0);
    1794          48 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
    1795             :                            TEXTOID, -1, 0);
    1796          48 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
    1797             :                            BOOLOID, -1, 0);
    1798             : 
    1799          48 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
    1800             : 
    1801             :         /* allocate memory for user context */
    1802          48 :         idx = (int *) palloc(sizeof(int[2]));
    1803          48 :         idx[0] = 0;             /* ACL array item index */
    1804          48 :         idx[1] = -1;            /* privilege type counter */
    1805          48 :         funcctx->user_fctx = (void *) idx;
    1806             : 
    1807          48 :         MemoryContextSwitchTo(oldcontext);
    1808             :     }
    1809             : 
    1810         144 :     funcctx = SRF_PERCALL_SETUP();
    1811         144 :     idx = (int *) funcctx->user_fctx;
    1812         144 :     aidat = ACL_DAT(acl);
    1813             : 
    1814             :     /* need test here in case acl has no items */
    1815        1488 :     while (idx[0] < ACL_NUM(acl))
    1816             :     {
    1817             :         AclItem    *aidata;
    1818             :         AclMode     priv_bit;
    1819             : 
    1820        1488 :         idx[1]++;
    1821        1488 :         if (idx[1] == N_ACL_RIGHTS)
    1822             :         {
    1823          96 :             idx[1] = 0;
    1824          96 :             idx[0]++;
    1825          96 :             if (idx[0] >= ACL_NUM(acl)) /* done */
    1826          48 :                 break;
    1827             :         }
    1828        1440 :         aidata = &aidat[idx[0]];
    1829        1440 :         priv_bit = UINT64CONST(1) << idx[1];
    1830             : 
    1831        1440 :         if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
    1832             :         {
    1833             :             Datum       result;
    1834             :             Datum       values[4];
    1835          96 :             bool        nulls[4] = {0};
    1836             :             HeapTuple   tuple;
    1837             : 
    1838          96 :             values[0] = ObjectIdGetDatum(aidata->ai_grantor);
    1839          96 :             values[1] = ObjectIdGetDatum(aidata->ai_grantee);
    1840          96 :             values[2] = CStringGetTextDatum(convert_aclright_to_string(priv_bit));
    1841          96 :             values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
    1842             : 
    1843          96 :             tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
    1844          96 :             result = HeapTupleGetDatum(tuple);
    1845             : 
    1846          96 :             SRF_RETURN_NEXT(funcctx, result);
    1847             :         }
    1848             :     }
    1849             : 
    1850          48 :     SRF_RETURN_DONE(funcctx);
    1851             : }
    1852             : 
    1853             : 
    1854             : /*
    1855             :  * has_table_privilege variants
    1856             :  *      These are all named "has_table_privilege" at the SQL level.
    1857             :  *      They take various combinations of relation name, relation OID,
    1858             :  *      user name, user OID, or implicit user = current_user.
    1859             :  *
    1860             :  *      The result is a boolean value: true if user has the indicated
    1861             :  *      privilege, false if not.  The variants that take a relation OID
    1862             :  *      return NULL if the OID doesn't exist (rather than failing, as
    1863             :  *      they did before Postgres 8.4).
    1864             :  */
    1865             : 
    1866             : /*
    1867             :  * has_table_privilege_name_name
    1868             :  *      Check user privileges on a table given
    1869             :  *      name username, text tablename, and text priv name.
    1870             :  */
    1871             : Datum
    1872         180 : has_table_privilege_name_name(PG_FUNCTION_ARGS)
    1873             : {
    1874         180 :     Name        rolename = PG_GETARG_NAME(0);
    1875         180 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    1876         180 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    1877             :     Oid         roleid;
    1878             :     Oid         tableoid;
    1879             :     AclMode     mode;
    1880             :     AclResult   aclresult;
    1881             : 
    1882         180 :     roleid = get_role_oid_or_public(NameStr(*rolename));
    1883         174 :     tableoid = convert_table_name(tablename);
    1884         174 :     mode = convert_table_priv_string(priv_type_text);
    1885             : 
    1886         174 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    1887             : 
    1888         174 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    1889             : }
    1890             : 
    1891             : /*
    1892             :  * has_table_privilege_name
    1893             :  *      Check user privileges on a table given
    1894             :  *      text tablename and text priv name.
    1895             :  *      current_user is assumed
    1896             :  */
    1897             : Datum
    1898          66 : has_table_privilege_name(PG_FUNCTION_ARGS)
    1899             : {
    1900          66 :     text       *tablename = PG_GETARG_TEXT_PP(0);
    1901          66 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    1902             :     Oid         roleid;
    1903             :     Oid         tableoid;
    1904             :     AclMode     mode;
    1905             :     AclResult   aclresult;
    1906             : 
    1907          66 :     roleid = GetUserId();
    1908          66 :     tableoid = convert_table_name(tablename);
    1909          60 :     mode = convert_table_priv_string(priv_type_text);
    1910             : 
    1911          54 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    1912             : 
    1913          54 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    1914             : }
    1915             : 
    1916             : /*
    1917             :  * has_table_privilege_name_id
    1918             :  *      Check user privileges on a table given
    1919             :  *      name usename, table oid, and text priv name.
    1920             :  */
    1921             : Datum
    1922          24 : has_table_privilege_name_id(PG_FUNCTION_ARGS)
    1923             : {
    1924          24 :     Name        username = PG_GETARG_NAME(0);
    1925          24 :     Oid         tableoid = PG_GETARG_OID(1);
    1926          24 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    1927             :     Oid         roleid;
    1928             :     AclMode     mode;
    1929             :     AclResult   aclresult;
    1930          24 :     bool        is_missing = false;
    1931             : 
    1932          24 :     roleid = get_role_oid_or_public(NameStr(*username));
    1933          24 :     mode = convert_table_priv_string(priv_type_text);
    1934             : 
    1935          24 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    1936             : 
    1937          24 :     if (is_missing)
    1938           0 :         PG_RETURN_NULL();
    1939             : 
    1940          24 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    1941             : }
    1942             : 
    1943             : /*
    1944             :  * has_table_privilege_id
    1945             :  *      Check user privileges on a table given
    1946             :  *      table oid, and text priv name.
    1947             :  *      current_user is assumed
    1948             :  */
    1949             : Datum
    1950         116 : has_table_privilege_id(PG_FUNCTION_ARGS)
    1951             : {
    1952         116 :     Oid         tableoid = PG_GETARG_OID(0);
    1953         116 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    1954             :     Oid         roleid;
    1955             :     AclMode     mode;
    1956             :     AclResult   aclresult;
    1957         116 :     bool        is_missing = false;
    1958             : 
    1959         116 :     roleid = GetUserId();
    1960         116 :     mode = convert_table_priv_string(priv_type_text);
    1961             : 
    1962         116 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    1963             : 
    1964         116 :     if (is_missing)
    1965           8 :         PG_RETURN_NULL();
    1966             : 
    1967         108 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    1968             : }
    1969             : 
    1970             : /*
    1971             :  * has_table_privilege_id_name
    1972             :  *      Check user privileges on a table given
    1973             :  *      roleid, text tablename, and text priv name.
    1974             :  */
    1975             : Datum
    1976          42 : has_table_privilege_id_name(PG_FUNCTION_ARGS)
    1977             : {
    1978          42 :     Oid         roleid = PG_GETARG_OID(0);
    1979          42 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    1980          42 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    1981             :     Oid         tableoid;
    1982             :     AclMode     mode;
    1983             :     AclResult   aclresult;
    1984             : 
    1985          42 :     tableoid = convert_table_name(tablename);
    1986          42 :     mode = convert_table_priv_string(priv_type_text);
    1987             : 
    1988          42 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    1989             : 
    1990          42 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    1991             : }
    1992             : 
    1993             : /*
    1994             :  * has_table_privilege_id_id
    1995             :  *      Check user privileges on a table given
    1996             :  *      roleid, table oid, and text priv name.
    1997             :  */
    1998             : Datum
    1999          36 : has_table_privilege_id_id(PG_FUNCTION_ARGS)
    2000             : {
    2001          36 :     Oid         roleid = PG_GETARG_OID(0);
    2002          36 :     Oid         tableoid = PG_GETARG_OID(1);
    2003          36 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2004             :     AclMode     mode;
    2005             :     AclResult   aclresult;
    2006          36 :     bool        is_missing = false;
    2007             : 
    2008          36 :     mode = convert_table_priv_string(priv_type_text);
    2009             : 
    2010          36 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    2011             : 
    2012          36 :     if (is_missing)
    2013           0 :         PG_RETURN_NULL();
    2014             : 
    2015          36 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2016             : }
    2017             : 
    2018             : /*
    2019             :  *      Support routines for has_table_privilege family.
    2020             :  */
    2021             : 
    2022             : /*
    2023             :  * Given a table name expressed as a string, look it up and return Oid
    2024             :  */
    2025             : static Oid
    2026         348 : convert_table_name(text *tablename)
    2027             : {
    2028             :     RangeVar   *relrv;
    2029             : 
    2030         348 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
    2031             : 
    2032             :     /* We might not even have permissions on this relation; don't lock it. */
    2033         348 :     return RangeVarGetRelid(relrv, NoLock, false);
    2034             : }
    2035             : 
    2036             : /*
    2037             :  * convert_table_priv_string
    2038             :  *      Convert text string to AclMode value.
    2039             :  */
    2040             : static AclMode
    2041         452 : convert_table_priv_string(text *priv_type_text)
    2042             : {
    2043             :     static const priv_map table_priv_map[] = {
    2044             :         {"SELECT", ACL_SELECT},
    2045             :         {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
    2046             :         {"INSERT", ACL_INSERT},
    2047             :         {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
    2048             :         {"UPDATE", ACL_UPDATE},
    2049             :         {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
    2050             :         {"DELETE", ACL_DELETE},
    2051             :         {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
    2052             :         {"TRUNCATE", ACL_TRUNCATE},
    2053             :         {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
    2054             :         {"REFERENCES", ACL_REFERENCES},
    2055             :         {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
    2056             :         {"TRIGGER", ACL_TRIGGER},
    2057             :         {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
    2058             :         {"MAINTAIN", ACL_MAINTAIN},
    2059             :         {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
    2060             :         {"RULE", 0},          /* ignore old RULE privileges */
    2061             :         {"RULE WITH GRANT OPTION", 0},
    2062             :         {NULL, 0}
    2063             :     };
    2064             : 
    2065         452 :     return convert_any_priv_string(priv_type_text, table_priv_map);
    2066             : }
    2067             : 
    2068             : /*
    2069             :  * has_sequence_privilege variants
    2070             :  *      These are all named "has_sequence_privilege" at the SQL level.
    2071             :  *      They take various combinations of relation name, relation OID,
    2072             :  *      user name, user OID, or implicit user = current_user.
    2073             :  *
    2074             :  *      The result is a boolean value: true if user has the indicated
    2075             :  *      privilege, false if not.  The variants that take a relation OID
    2076             :  *      return NULL if the OID doesn't exist.
    2077             :  */
    2078             : 
    2079             : /*
    2080             :  * has_sequence_privilege_name_name
    2081             :  *      Check user privileges on a sequence given
    2082             :  *      name username, text sequencename, and text priv name.
    2083             :  */
    2084             : Datum
    2085          18 : has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
    2086             : {
    2087          18 :     Name        rolename = PG_GETARG_NAME(0);
    2088          18 :     text       *sequencename = PG_GETARG_TEXT_PP(1);
    2089          18 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2090             :     Oid         roleid;
    2091             :     Oid         sequenceoid;
    2092             :     AclMode     mode;
    2093             :     AclResult   aclresult;
    2094             : 
    2095          18 :     roleid = get_role_oid_or_public(NameStr(*rolename));
    2096          18 :     mode = convert_sequence_priv_string(priv_type_text);
    2097          12 :     sequenceoid = convert_table_name(sequencename);
    2098          12 :     if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
    2099           6 :         ereport(ERROR,
    2100             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2101             :                  errmsg("\"%s\" is not a sequence",
    2102             :                         text_to_cstring(sequencename))));
    2103             : 
    2104           6 :     aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
    2105             : 
    2106           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2107             : }
    2108             : 
    2109             : /*
    2110             :  * has_sequence_privilege_name
    2111             :  *      Check user privileges on a sequence given
    2112             :  *      text sequencename and text priv name.
    2113             :  *      current_user is assumed
    2114             :  */
    2115             : Datum
    2116           6 : has_sequence_privilege_name(PG_FUNCTION_ARGS)
    2117             : {
    2118           6 :     text       *sequencename = PG_GETARG_TEXT_PP(0);
    2119           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    2120             :     Oid         roleid;
    2121             :     Oid         sequenceoid;
    2122             :     AclMode     mode;
    2123             :     AclResult   aclresult;
    2124             : 
    2125           6 :     roleid = GetUserId();
    2126           6 :     mode = convert_sequence_priv_string(priv_type_text);
    2127           6 :     sequenceoid = convert_table_name(sequencename);
    2128           6 :     if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
    2129           0 :         ereport(ERROR,
    2130             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2131             :                  errmsg("\"%s\" is not a sequence",
    2132             :                         text_to_cstring(sequencename))));
    2133             : 
    2134           6 :     aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
    2135             : 
    2136           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2137             : }
    2138             : 
    2139             : /*
    2140             :  * has_sequence_privilege_name_id
    2141             :  *      Check user privileges on a sequence given
    2142             :  *      name usename, sequence oid, and text priv name.
    2143             :  */
    2144             : Datum
    2145           0 : has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
    2146             : {
    2147           0 :     Name        username = PG_GETARG_NAME(0);
    2148           0 :     Oid         sequenceoid = PG_GETARG_OID(1);
    2149           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2150             :     Oid         roleid;
    2151             :     AclMode     mode;
    2152             :     AclResult   aclresult;
    2153             :     char        relkind;
    2154           0 :     bool        is_missing = false;
    2155             : 
    2156           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    2157           0 :     mode = convert_sequence_priv_string(priv_type_text);
    2158           0 :     relkind = get_rel_relkind(sequenceoid);
    2159           0 :     if (relkind == '\0')
    2160           0 :         PG_RETURN_NULL();
    2161           0 :     else if (relkind != RELKIND_SEQUENCE)
    2162           0 :         ereport(ERROR,
    2163             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2164             :                  errmsg("\"%s\" is not a sequence",
    2165             :                         get_rel_name(sequenceoid))));
    2166             : 
    2167           0 :     aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
    2168             : 
    2169           0 :     if (is_missing)
    2170           0 :         PG_RETURN_NULL();
    2171             : 
    2172           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2173             : }
    2174             : 
    2175             : /*
    2176             :  * has_sequence_privilege_id
    2177             :  *      Check user privileges on a sequence given
    2178             :  *      sequence oid, and text priv name.
    2179             :  *      current_user is assumed
    2180             :  */
    2181             : Datum
    2182         114 : has_sequence_privilege_id(PG_FUNCTION_ARGS)
    2183             : {
    2184         114 :     Oid         sequenceoid = PG_GETARG_OID(0);
    2185         114 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    2186             :     Oid         roleid;
    2187             :     AclMode     mode;
    2188             :     AclResult   aclresult;
    2189             :     char        relkind;
    2190         114 :     bool        is_missing = false;
    2191             : 
    2192         114 :     roleid = GetUserId();
    2193         114 :     mode = convert_sequence_priv_string(priv_type_text);
    2194         114 :     relkind = get_rel_relkind(sequenceoid);
    2195         114 :     if (relkind == '\0')
    2196           0 :         PG_RETURN_NULL();
    2197         114 :     else if (relkind != RELKIND_SEQUENCE)
    2198           0 :         ereport(ERROR,
    2199             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2200             :                  errmsg("\"%s\" is not a sequence",
    2201             :                         get_rel_name(sequenceoid))));
    2202             : 
    2203         114 :     aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
    2204             : 
    2205         114 :     if (is_missing)
    2206           0 :         PG_RETURN_NULL();
    2207             : 
    2208         114 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2209             : }
    2210             : 
    2211             : /*
    2212             :  * has_sequence_privilege_id_name
    2213             :  *      Check user privileges on a sequence given
    2214             :  *      roleid, text sequencename, and text priv name.
    2215             :  */
    2216             : Datum
    2217           0 : has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
    2218             : {
    2219           0 :     Oid         roleid = PG_GETARG_OID(0);
    2220           0 :     text       *sequencename = PG_GETARG_TEXT_PP(1);
    2221           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2222             :     Oid         sequenceoid;
    2223             :     AclMode     mode;
    2224             :     AclResult   aclresult;
    2225             : 
    2226           0 :     mode = convert_sequence_priv_string(priv_type_text);
    2227           0 :     sequenceoid = convert_table_name(sequencename);
    2228           0 :     if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
    2229           0 :         ereport(ERROR,
    2230             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2231             :                  errmsg("\"%s\" is not a sequence",
    2232             :                         text_to_cstring(sequencename))));
    2233             : 
    2234           0 :     aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
    2235             : 
    2236           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2237             : }
    2238             : 
    2239             : /*
    2240             :  * has_sequence_privilege_id_id
    2241             :  *      Check user privileges on a sequence given
    2242             :  *      roleid, sequence oid, and text priv name.
    2243             :  */
    2244             : Datum
    2245           0 : has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
    2246             : {
    2247           0 :     Oid         roleid = PG_GETARG_OID(0);
    2248           0 :     Oid         sequenceoid = PG_GETARG_OID(1);
    2249           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2250             :     AclMode     mode;
    2251             :     AclResult   aclresult;
    2252             :     char        relkind;
    2253           0 :     bool        is_missing = false;
    2254             : 
    2255           0 :     mode = convert_sequence_priv_string(priv_type_text);
    2256           0 :     relkind = get_rel_relkind(sequenceoid);
    2257           0 :     if (relkind == '\0')
    2258           0 :         PG_RETURN_NULL();
    2259           0 :     else if (relkind != RELKIND_SEQUENCE)
    2260           0 :         ereport(ERROR,
    2261             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2262             :                  errmsg("\"%s\" is not a sequence",
    2263             :                         get_rel_name(sequenceoid))));
    2264             : 
    2265           0 :     aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
    2266             : 
    2267           0 :     if (is_missing)
    2268           0 :         PG_RETURN_NULL();
    2269             : 
    2270           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2271             : }
    2272             : 
    2273             : /*
    2274             :  * convert_sequence_priv_string
    2275             :  *      Convert text string to AclMode value.
    2276             :  */
    2277             : static AclMode
    2278         138 : convert_sequence_priv_string(text *priv_type_text)
    2279             : {
    2280             :     static const priv_map sequence_priv_map[] = {
    2281             :         {"USAGE", ACL_USAGE},
    2282             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    2283             :         {"SELECT", ACL_SELECT},
    2284             :         {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
    2285             :         {"UPDATE", ACL_UPDATE},
    2286             :         {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
    2287             :         {NULL, 0}
    2288             :     };
    2289             : 
    2290         138 :     return convert_any_priv_string(priv_type_text, sequence_priv_map);
    2291             : }
    2292             : 
    2293             : 
    2294             : /*
    2295             :  * has_any_column_privilege variants
    2296             :  *      These are all named "has_any_column_privilege" at the SQL level.
    2297             :  *      They take various combinations of relation name, relation OID,
    2298             :  *      user name, user OID, or implicit user = current_user.
    2299             :  *
    2300             :  *      The result is a boolean value: true if user has the indicated
    2301             :  *      privilege for any column of the table, false if not.  The variants
    2302             :  *      that take a relation OID return NULL if the OID doesn't exist.
    2303             :  */
    2304             : 
    2305             : /*
    2306             :  * has_any_column_privilege_name_name
    2307             :  *      Check user privileges on any column of a table given
    2308             :  *      name username, text tablename, and text priv name.
    2309             :  */
    2310             : Datum
    2311           0 : has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
    2312             : {
    2313           0 :     Name        rolename = PG_GETARG_NAME(0);
    2314           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2315           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2316             :     Oid         roleid;
    2317             :     Oid         tableoid;
    2318             :     AclMode     mode;
    2319             :     AclResult   aclresult;
    2320             : 
    2321           0 :     roleid = get_role_oid_or_public(NameStr(*rolename));
    2322           0 :     tableoid = convert_table_name(tablename);
    2323           0 :     mode = convert_column_priv_string(priv_type_text);
    2324             : 
    2325             :     /* First check at table level, then examine each column if needed */
    2326           0 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    2327           0 :     if (aclresult != ACLCHECK_OK)
    2328           0 :         aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
    2329             :                                               ACLMASK_ANY);
    2330             : 
    2331           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2332             : }
    2333             : 
    2334             : /*
    2335             :  * has_any_column_privilege_name
    2336             :  *      Check user privileges on any column of a table given
    2337             :  *      text tablename and text priv name.
    2338             :  *      current_user is assumed
    2339             :  */
    2340             : Datum
    2341           0 : has_any_column_privilege_name(PG_FUNCTION_ARGS)
    2342             : {
    2343           0 :     text       *tablename = PG_GETARG_TEXT_PP(0);
    2344           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    2345             :     Oid         roleid;
    2346             :     Oid         tableoid;
    2347             :     AclMode     mode;
    2348             :     AclResult   aclresult;
    2349             : 
    2350           0 :     roleid = GetUserId();
    2351           0 :     tableoid = convert_table_name(tablename);
    2352           0 :     mode = convert_column_priv_string(priv_type_text);
    2353             : 
    2354             :     /* First check at table level, then examine each column if needed */
    2355           0 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    2356           0 :     if (aclresult != ACLCHECK_OK)
    2357           0 :         aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
    2358             :                                               ACLMASK_ANY);
    2359             : 
    2360           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2361             : }
    2362             : 
    2363             : /*
    2364             :  * has_any_column_privilege_name_id
    2365             :  *      Check user privileges on any column of a table given
    2366             :  *      name usename, table oid, and text priv name.
    2367             :  */
    2368             : Datum
    2369           0 : has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
    2370             : {
    2371           0 :     Name        username = PG_GETARG_NAME(0);
    2372           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2373           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2374             :     Oid         roleid;
    2375             :     AclMode     mode;
    2376             :     AclResult   aclresult;
    2377           0 :     bool        is_missing = false;
    2378             : 
    2379           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    2380           0 :     mode = convert_column_priv_string(priv_type_text);
    2381             : 
    2382             :     /* First check at table level, then examine each column if needed */
    2383           0 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    2384           0 :     if (aclresult != ACLCHECK_OK)
    2385             :     {
    2386           0 :         if (is_missing)
    2387           0 :             PG_RETURN_NULL();
    2388           0 :         aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
    2389             :                                                   ACLMASK_ANY, &is_missing);
    2390           0 :         if (is_missing)
    2391           0 :             PG_RETURN_NULL();
    2392             :     }
    2393             : 
    2394           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2395             : }
    2396             : 
    2397             : /*
    2398             :  * has_any_column_privilege_id
    2399             :  *      Check user privileges on any column of a table given
    2400             :  *      table oid, and text priv name.
    2401             :  *      current_user is assumed
    2402             :  */
    2403             : Datum
    2404           0 : has_any_column_privilege_id(PG_FUNCTION_ARGS)
    2405             : {
    2406           0 :     Oid         tableoid = PG_GETARG_OID(0);
    2407           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    2408             :     Oid         roleid;
    2409             :     AclMode     mode;
    2410             :     AclResult   aclresult;
    2411           0 :     bool        is_missing = false;
    2412             : 
    2413           0 :     roleid = GetUserId();
    2414           0 :     mode = convert_column_priv_string(priv_type_text);
    2415             : 
    2416             :     /* First check at table level, then examine each column if needed */
    2417           0 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    2418           0 :     if (aclresult != ACLCHECK_OK)
    2419             :     {
    2420           0 :         if (is_missing)
    2421           0 :             PG_RETURN_NULL();
    2422           0 :         aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
    2423             :                                                   ACLMASK_ANY, &is_missing);
    2424           0 :         if (is_missing)
    2425           0 :             PG_RETURN_NULL();
    2426             :     }
    2427             : 
    2428           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2429             : }
    2430             : 
    2431             : /*
    2432             :  * has_any_column_privilege_id_name
    2433             :  *      Check user privileges on any column of a table given
    2434             :  *      roleid, text tablename, and text priv name.
    2435             :  */
    2436             : Datum
    2437           0 : has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
    2438             : {
    2439           0 :     Oid         roleid = PG_GETARG_OID(0);
    2440           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2441           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2442             :     Oid         tableoid;
    2443             :     AclMode     mode;
    2444             :     AclResult   aclresult;
    2445             : 
    2446           0 :     tableoid = convert_table_name(tablename);
    2447           0 :     mode = convert_column_priv_string(priv_type_text);
    2448             : 
    2449             :     /* First check at table level, then examine each column if needed */
    2450           0 :     aclresult = pg_class_aclcheck(tableoid, roleid, mode);
    2451           0 :     if (aclresult != ACLCHECK_OK)
    2452           0 :         aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
    2453             :                                               ACLMASK_ANY);
    2454             : 
    2455           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2456             : }
    2457             : 
    2458             : /*
    2459             :  * has_any_column_privilege_id_id
    2460             :  *      Check user privileges on any column of a table given
    2461             :  *      roleid, table oid, and text priv name.
    2462             :  */
    2463             : Datum
    2464           0 : has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
    2465             : {
    2466           0 :     Oid         roleid = PG_GETARG_OID(0);
    2467           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2468           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2469             :     AclMode     mode;
    2470             :     AclResult   aclresult;
    2471           0 :     bool        is_missing = false;
    2472             : 
    2473           0 :     mode = convert_column_priv_string(priv_type_text);
    2474             : 
    2475             :     /* First check at table level, then examine each column if needed */
    2476           0 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    2477           0 :     if (aclresult != ACLCHECK_OK)
    2478             :     {
    2479           0 :         if (is_missing)
    2480           0 :             PG_RETURN_NULL();
    2481           0 :         aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
    2482             :                                                   ACLMASK_ANY, &is_missing);
    2483           0 :         if (is_missing)
    2484           0 :             PG_RETURN_NULL();
    2485             :     }
    2486             : 
    2487           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2488             : }
    2489             : 
    2490             : 
    2491             : /*
    2492             :  * has_column_privilege variants
    2493             :  *      These are all named "has_column_privilege" at the SQL level.
    2494             :  *      They take various combinations of relation name, relation OID,
    2495             :  *      column name, column attnum, user name, user OID, or
    2496             :  *      implicit user = current_user.
    2497             :  *
    2498             :  *      The result is a boolean value: true if user has the indicated
    2499             :  *      privilege, false if not.  The variants that take a relation OID
    2500             :  *      return NULL (rather than throwing an error) if that relation OID
    2501             :  *      doesn't exist.  Likewise, the variants that take an integer attnum
    2502             :  *      return NULL (rather than throwing an error) if there is no such
    2503             :  *      pg_attribute entry.  All variants return NULL if an attisdropped
    2504             :  *      column is selected.  These rules are meant to avoid unnecessary
    2505             :  *      failures in queries that scan pg_attribute.
    2506             :  */
    2507             : 
    2508             : /*
    2509             :  * column_privilege_check: check column privileges, but don't throw an error
    2510             :  *      for dropped column or table
    2511             :  *
    2512             :  * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
    2513             :  */
    2514             : static int
    2515        1840 : column_privilege_check(Oid tableoid, AttrNumber attnum,
    2516             :                        Oid roleid, AclMode mode)
    2517             : {
    2518             :     AclResult   aclresult;
    2519        1840 :     bool        is_missing = false;
    2520             : 
    2521             :     /*
    2522             :      * If convert_column_name failed, we can just return -1 immediately.
    2523             :      */
    2524        1840 :     if (attnum == InvalidAttrNumber)
    2525          12 :         return -1;
    2526             : 
    2527             :     /*
    2528             :      * Check for column-level privileges first. This serves in part as a check
    2529             :      * on whether the column even exists, so we need to do it before checking
    2530             :      * table-level privilege.
    2531             :      */
    2532        1828 :     aclresult = pg_attribute_aclcheck_ext(tableoid, attnum, roleid,
    2533             :                                           mode, &is_missing);
    2534        1828 :     if (aclresult == ACLCHECK_OK)
    2535          12 :         return 1;
    2536        1816 :     else if (is_missing)
    2537          42 :         return -1;
    2538             : 
    2539             :     /* Next check if we have the privilege at the table level */
    2540        1774 :     aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
    2541        1774 :     if (aclresult == ACLCHECK_OK)
    2542        1774 :         return 1;
    2543           0 :     else if (is_missing)
    2544           0 :         return -1;
    2545             :     else
    2546           0 :         return 0;
    2547             : }
    2548             : 
    2549             : /*
    2550             :  * has_column_privilege_name_name_name
    2551             :  *      Check user privileges on a column given
    2552             :  *      name username, text tablename, text colname, and text priv name.
    2553             :  */
    2554             : Datum
    2555           0 : has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
    2556             : {
    2557           0 :     Name        rolename = PG_GETARG_NAME(0);
    2558           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2559           0 :     text       *column = PG_GETARG_TEXT_PP(2);
    2560           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2561             :     Oid         roleid;
    2562             :     Oid         tableoid;
    2563             :     AttrNumber  colattnum;
    2564             :     AclMode     mode;
    2565             :     int         privresult;
    2566             : 
    2567           0 :     roleid = get_role_oid_or_public(NameStr(*rolename));
    2568           0 :     tableoid = convert_table_name(tablename);
    2569           0 :     colattnum = convert_column_name(tableoid, column);
    2570           0 :     mode = convert_column_priv_string(priv_type_text);
    2571             : 
    2572           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2573           0 :     if (privresult < 0)
    2574           0 :         PG_RETURN_NULL();
    2575           0 :     PG_RETURN_BOOL(privresult);
    2576             : }
    2577             : 
    2578             : /*
    2579             :  * has_column_privilege_name_name_attnum
    2580             :  *      Check user privileges on a column given
    2581             :  *      name username, text tablename, int attnum, and text priv name.
    2582             :  */
    2583             : Datum
    2584           0 : has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
    2585             : {
    2586           0 :     Name        rolename = PG_GETARG_NAME(0);
    2587           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2588           0 :     AttrNumber  colattnum = PG_GETARG_INT16(2);
    2589           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2590             :     Oid         roleid;
    2591             :     Oid         tableoid;
    2592             :     AclMode     mode;
    2593             :     int         privresult;
    2594             : 
    2595           0 :     roleid = get_role_oid_or_public(NameStr(*rolename));
    2596           0 :     tableoid = convert_table_name(tablename);
    2597           0 :     mode = convert_column_priv_string(priv_type_text);
    2598             : 
    2599           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2600           0 :     if (privresult < 0)
    2601           0 :         PG_RETURN_NULL();
    2602           0 :     PG_RETURN_BOOL(privresult);
    2603             : }
    2604             : 
    2605             : /*
    2606             :  * has_column_privilege_name_id_name
    2607             :  *      Check user privileges on a column given
    2608             :  *      name username, table oid, text colname, and text priv name.
    2609             :  */
    2610             : Datum
    2611           0 : has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
    2612             : {
    2613           0 :     Name        username = PG_GETARG_NAME(0);
    2614           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2615           0 :     text       *column = PG_GETARG_TEXT_PP(2);
    2616           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2617             :     Oid         roleid;
    2618             :     AttrNumber  colattnum;
    2619             :     AclMode     mode;
    2620             :     int         privresult;
    2621             : 
    2622           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    2623           0 :     colattnum = convert_column_name(tableoid, column);
    2624           0 :     mode = convert_column_priv_string(priv_type_text);
    2625             : 
    2626           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2627           0 :     if (privresult < 0)
    2628           0 :         PG_RETURN_NULL();
    2629           0 :     PG_RETURN_BOOL(privresult);
    2630             : }
    2631             : 
    2632             : /*
    2633             :  * has_column_privilege_name_id_attnum
    2634             :  *      Check user privileges on a column given
    2635             :  *      name username, table oid, int attnum, and text priv name.
    2636             :  */
    2637             : Datum
    2638           0 : has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
    2639             : {
    2640           0 :     Name        username = PG_GETARG_NAME(0);
    2641           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2642           0 :     AttrNumber  colattnum = PG_GETARG_INT16(2);
    2643           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2644             :     Oid         roleid;
    2645             :     AclMode     mode;
    2646             :     int         privresult;
    2647             : 
    2648           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    2649           0 :     mode = convert_column_priv_string(priv_type_text);
    2650             : 
    2651           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2652           0 :     if (privresult < 0)
    2653           0 :         PG_RETURN_NULL();
    2654           0 :     PG_RETURN_BOOL(privresult);
    2655             : }
    2656             : 
    2657             : /*
    2658             :  * has_column_privilege_id_name_name
    2659             :  *      Check user privileges on a column given
    2660             :  *      oid roleid, text tablename, text colname, and text priv name.
    2661             :  */
    2662             : Datum
    2663           0 : has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
    2664             : {
    2665           0 :     Oid         roleid = PG_GETARG_OID(0);
    2666           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2667           0 :     text       *column = PG_GETARG_TEXT_PP(2);
    2668           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2669             :     Oid         tableoid;
    2670             :     AttrNumber  colattnum;
    2671             :     AclMode     mode;
    2672             :     int         privresult;
    2673             : 
    2674           0 :     tableoid = convert_table_name(tablename);
    2675           0 :     colattnum = convert_column_name(tableoid, column);
    2676           0 :     mode = convert_column_priv_string(priv_type_text);
    2677             : 
    2678           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2679           0 :     if (privresult < 0)
    2680           0 :         PG_RETURN_NULL();
    2681           0 :     PG_RETURN_BOOL(privresult);
    2682             : }
    2683             : 
    2684             : /*
    2685             :  * has_column_privilege_id_name_attnum
    2686             :  *      Check user privileges on a column given
    2687             :  *      oid roleid, text tablename, int attnum, and text priv name.
    2688             :  */
    2689             : Datum
    2690           0 : has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
    2691             : {
    2692           0 :     Oid         roleid = PG_GETARG_OID(0);
    2693           0 :     text       *tablename = PG_GETARG_TEXT_PP(1);
    2694           0 :     AttrNumber  colattnum = PG_GETARG_INT16(2);
    2695           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2696             :     Oid         tableoid;
    2697             :     AclMode     mode;
    2698             :     int         privresult;
    2699             : 
    2700           0 :     tableoid = convert_table_name(tablename);
    2701           0 :     mode = convert_column_priv_string(priv_type_text);
    2702             : 
    2703           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2704           0 :     if (privresult < 0)
    2705           0 :         PG_RETURN_NULL();
    2706           0 :     PG_RETURN_BOOL(privresult);
    2707             : }
    2708             : 
    2709             : /*
    2710             :  * has_column_privilege_id_id_name
    2711             :  *      Check user privileges on a column given
    2712             :  *      oid roleid, table oid, text colname, and text priv name.
    2713             :  */
    2714             : Datum
    2715           0 : has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
    2716             : {
    2717           0 :     Oid         roleid = PG_GETARG_OID(0);
    2718           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2719           0 :     text       *column = PG_GETARG_TEXT_PP(2);
    2720           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2721             :     AttrNumber  colattnum;
    2722             :     AclMode     mode;
    2723             :     int         privresult;
    2724             : 
    2725           0 :     colattnum = convert_column_name(tableoid, column);
    2726           0 :     mode = convert_column_priv_string(priv_type_text);
    2727             : 
    2728           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2729           0 :     if (privresult < 0)
    2730           0 :         PG_RETURN_NULL();
    2731           0 :     PG_RETURN_BOOL(privresult);
    2732             : }
    2733             : 
    2734             : /*
    2735             :  * has_column_privilege_id_id_attnum
    2736             :  *      Check user privileges on a column given
    2737             :  *      oid roleid, table oid, int attnum, and text priv name.
    2738             :  */
    2739             : Datum
    2740           0 : has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
    2741             : {
    2742           0 :     Oid         roleid = PG_GETARG_OID(0);
    2743           0 :     Oid         tableoid = PG_GETARG_OID(1);
    2744           0 :     AttrNumber  colattnum = PG_GETARG_INT16(2);
    2745           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(3);
    2746             :     AclMode     mode;
    2747             :     int         privresult;
    2748             : 
    2749           0 :     mode = convert_column_priv_string(priv_type_text);
    2750             : 
    2751           0 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2752           0 :     if (privresult < 0)
    2753           0 :         PG_RETURN_NULL();
    2754           0 :     PG_RETURN_BOOL(privresult);
    2755             : }
    2756             : 
    2757             : /*
    2758             :  * has_column_privilege_name_name
    2759             :  *      Check user privileges on a column given
    2760             :  *      text tablename, text colname, and text priv name.
    2761             :  *      current_user is assumed
    2762             :  */
    2763             : Datum
    2764          18 : has_column_privilege_name_name(PG_FUNCTION_ARGS)
    2765             : {
    2766          18 :     text       *tablename = PG_GETARG_TEXT_PP(0);
    2767          18 :     text       *column = PG_GETARG_TEXT_PP(1);
    2768          18 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2769             :     Oid         roleid;
    2770             :     Oid         tableoid;
    2771             :     AttrNumber  colattnum;
    2772             :     AclMode     mode;
    2773             :     int         privresult;
    2774             : 
    2775          18 :     roleid = GetUserId();
    2776          18 :     tableoid = convert_table_name(tablename);
    2777          18 :     colattnum = convert_column_name(tableoid, column);
    2778           6 :     mode = convert_column_priv_string(priv_type_text);
    2779             : 
    2780           6 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2781           6 :     if (privresult < 0)
    2782           6 :         PG_RETURN_NULL();
    2783           0 :     PG_RETURN_BOOL(privresult);
    2784             : }
    2785             : 
    2786             : /*
    2787             :  * has_column_privilege_name_attnum
    2788             :  *      Check user privileges on a column given
    2789             :  *      text tablename, int attnum, and text priv name.
    2790             :  *      current_user is assumed
    2791             :  */
    2792             : Datum
    2793          30 : has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
    2794             : {
    2795          30 :     text       *tablename = PG_GETARG_TEXT_PP(0);
    2796          30 :     AttrNumber  colattnum = PG_GETARG_INT16(1);
    2797          30 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2798             :     Oid         roleid;
    2799             :     Oid         tableoid;
    2800             :     AclMode     mode;
    2801             :     int         privresult;
    2802             : 
    2803          30 :     roleid = GetUserId();
    2804          30 :     tableoid = convert_table_name(tablename);
    2805          30 :     mode = convert_column_priv_string(priv_type_text);
    2806             : 
    2807          30 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2808          30 :     if (privresult < 0)
    2809          30 :         PG_RETURN_NULL();
    2810           0 :     PG_RETURN_BOOL(privresult);
    2811             : }
    2812             : 
    2813             : /*
    2814             :  * has_column_privilege_id_name
    2815             :  *      Check user privileges on a column given
    2816             :  *      table oid, text colname, and text priv name.
    2817             :  *      current_user is assumed
    2818             :  */
    2819             : Datum
    2820           6 : has_column_privilege_id_name(PG_FUNCTION_ARGS)
    2821             : {
    2822           6 :     Oid         tableoid = PG_GETARG_OID(0);
    2823           6 :     text       *column = PG_GETARG_TEXT_PP(1);
    2824           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2825             :     Oid         roleid;
    2826             :     AttrNumber  colattnum;
    2827             :     AclMode     mode;
    2828             :     int         privresult;
    2829             : 
    2830           6 :     roleid = GetUserId();
    2831           6 :     colattnum = convert_column_name(tableoid, column);
    2832           6 :     mode = convert_column_priv_string(priv_type_text);
    2833             : 
    2834           6 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2835           6 :     if (privresult < 0)
    2836           6 :         PG_RETURN_NULL();
    2837           0 :     PG_RETURN_BOOL(privresult);
    2838             : }
    2839             : 
    2840             : /*
    2841             :  * has_column_privilege_id_attnum
    2842             :  *      Check user privileges on a column given
    2843             :  *      table oid, int attnum, and text priv name.
    2844             :  *      current_user is assumed
    2845             :  */
    2846             : Datum
    2847        1798 : has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
    2848             : {
    2849        1798 :     Oid         tableoid = PG_GETARG_OID(0);
    2850        1798 :     AttrNumber  colattnum = PG_GETARG_INT16(1);
    2851        1798 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2852             :     Oid         roleid;
    2853             :     AclMode     mode;
    2854             :     int         privresult;
    2855             : 
    2856        1798 :     roleid = GetUserId();
    2857        1798 :     mode = convert_column_priv_string(priv_type_text);
    2858             : 
    2859        1798 :     privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
    2860        1798 :     if (privresult < 0)
    2861          12 :         PG_RETURN_NULL();
    2862        1786 :     PG_RETURN_BOOL(privresult);
    2863             : }
    2864             : 
    2865             : /*
    2866             :  *      Support routines for has_column_privilege family.
    2867             :  */
    2868             : 
    2869             : /*
    2870             :  * Given a table OID and a column name expressed as a string, look it up
    2871             :  * and return the column number.  Returns InvalidAttrNumber in cases
    2872             :  * where caller should return NULL instead of failing.
    2873             :  */
    2874             : static AttrNumber
    2875          24 : convert_column_name(Oid tableoid, text *column)
    2876             : {
    2877             :     char       *colname;
    2878             :     HeapTuple   attTuple;
    2879             :     AttrNumber  attnum;
    2880             : 
    2881          24 :     colname = text_to_cstring(column);
    2882             : 
    2883             :     /*
    2884             :      * We don't use get_attnum() here because it will report that dropped
    2885             :      * columns don't exist.  We need to treat dropped columns differently from
    2886             :      * nonexistent columns.
    2887             :      */
    2888          24 :     attTuple = SearchSysCache2(ATTNAME,
    2889             :                                ObjectIdGetDatum(tableoid),
    2890             :                                CStringGetDatum(colname));
    2891          24 :     if (HeapTupleIsValid(attTuple))
    2892             :     {
    2893             :         Form_pg_attribute attributeForm;
    2894             : 
    2895           6 :         attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
    2896             :         /* We want to return NULL for dropped columns */
    2897           6 :         if (attributeForm->attisdropped)
    2898           6 :             attnum = InvalidAttrNumber;
    2899             :         else
    2900           0 :             attnum = attributeForm->attnum;
    2901           6 :         ReleaseSysCache(attTuple);
    2902             :     }
    2903             :     else
    2904             :     {
    2905          18 :         char       *tablename = get_rel_name(tableoid);
    2906             : 
    2907             :         /*
    2908             :          * If the table OID is bogus, or it's just been dropped, we'll get
    2909             :          * NULL back.  In such cases we want has_column_privilege to return
    2910             :          * NULL too, so just return InvalidAttrNumber.
    2911             :          */
    2912          18 :         if (tablename != NULL)
    2913             :         {
    2914             :             /* tableoid exists, colname does not, so throw error */
    2915          12 :             ereport(ERROR,
    2916             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    2917             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    2918             :                             colname, tablename)));
    2919             :         }
    2920             :         /* tableoid doesn't exist, so act like attisdropped case */
    2921           6 :         attnum = InvalidAttrNumber;
    2922             :     }
    2923             : 
    2924          12 :     pfree(colname);
    2925          12 :     return attnum;
    2926             : }
    2927             : 
    2928             : /*
    2929             :  * convert_column_priv_string
    2930             :  *      Convert text string to AclMode value.
    2931             :  */
    2932             : static AclMode
    2933        1840 : convert_column_priv_string(text *priv_type_text)
    2934             : {
    2935             :     static const priv_map column_priv_map[] = {
    2936             :         {"SELECT", ACL_SELECT},
    2937             :         {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
    2938             :         {"INSERT", ACL_INSERT},
    2939             :         {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
    2940             :         {"UPDATE", ACL_UPDATE},
    2941             :         {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
    2942             :         {"REFERENCES", ACL_REFERENCES},
    2943             :         {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
    2944             :         {NULL, 0}
    2945             :     };
    2946             : 
    2947        1840 :     return convert_any_priv_string(priv_type_text, column_priv_map);
    2948             : }
    2949             : 
    2950             : 
    2951             : /*
    2952             :  * has_database_privilege variants
    2953             :  *      These are all named "has_database_privilege" at the SQL level.
    2954             :  *      They take various combinations of database name, database OID,
    2955             :  *      user name, user OID, or implicit user = current_user.
    2956             :  *
    2957             :  *      The result is a boolean value: true if user has the indicated
    2958             :  *      privilege, false if not, or NULL if object doesn't exist.
    2959             :  */
    2960             : 
    2961             : /*
    2962             :  * has_database_privilege_name_name
    2963             :  *      Check user privileges on a database given
    2964             :  *      name username, text databasename, and text priv name.
    2965             :  */
    2966             : Datum
    2967           0 : has_database_privilege_name_name(PG_FUNCTION_ARGS)
    2968             : {
    2969           0 :     Name        username = PG_GETARG_NAME(0);
    2970           0 :     text       *databasename = PG_GETARG_TEXT_PP(1);
    2971           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    2972             :     Oid         roleid;
    2973             :     Oid         databaseoid;
    2974             :     AclMode     mode;
    2975             :     AclResult   aclresult;
    2976             : 
    2977           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    2978           0 :     databaseoid = convert_database_name(databasename);
    2979           0 :     mode = convert_database_priv_string(priv_type_text);
    2980             : 
    2981           0 :     aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
    2982             : 
    2983           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    2984             : }
    2985             : 
    2986             : /*
    2987             :  * has_database_privilege_name
    2988             :  *      Check user privileges on a database given
    2989             :  *      text databasename and text priv name.
    2990             :  *      current_user is assumed
    2991             :  */
    2992             : Datum
    2993           0 : has_database_privilege_name(PG_FUNCTION_ARGS)
    2994             : {
    2995           0 :     text       *databasename = PG_GETARG_TEXT_PP(0);
    2996           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    2997             :     Oid         roleid;
    2998             :     Oid         databaseoid;
    2999             :     AclMode     mode;
    3000             :     AclResult   aclresult;
    3001             : 
    3002           0 :     roleid = GetUserId();
    3003           0 :     databaseoid = convert_database_name(databasename);
    3004           0 :     mode = convert_database_priv_string(priv_type_text);
    3005             : 
    3006           0 :     aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
    3007             : 
    3008           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3009             : }
    3010             : 
    3011             : /*
    3012             :  * has_database_privilege_name_id
    3013             :  *      Check user privileges on a database given
    3014             :  *      name usename, database oid, and text priv name.
    3015             :  */
    3016             : Datum
    3017           0 : has_database_privilege_name_id(PG_FUNCTION_ARGS)
    3018             : {
    3019           0 :     Name        username = PG_GETARG_NAME(0);
    3020           0 :     Oid         databaseoid = PG_GETARG_OID(1);
    3021           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3022             :     Oid         roleid;
    3023             :     AclMode     mode;
    3024             :     AclResult   aclresult;
    3025           0 :     bool        is_missing = false;
    3026             : 
    3027           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    3028           0 :     mode = convert_database_priv_string(priv_type_text);
    3029             : 
    3030           0 :     aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
    3031             :                                     roleid, mode,
    3032             :                                     &is_missing);
    3033             : 
    3034           0 :     if (is_missing)
    3035           0 :         PG_RETURN_NULL();
    3036             : 
    3037           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3038             : }
    3039             : 
    3040             : /*
    3041             :  * has_database_privilege_id
    3042             :  *      Check user privileges on a database given
    3043             :  *      database oid, and text priv name.
    3044             :  *      current_user is assumed
    3045             :  */
    3046             : Datum
    3047           0 : has_database_privilege_id(PG_FUNCTION_ARGS)
    3048             : {
    3049           0 :     Oid         databaseoid = PG_GETARG_OID(0);
    3050           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3051             :     Oid         roleid;
    3052             :     AclMode     mode;
    3053             :     AclResult   aclresult;
    3054           0 :     bool        is_missing = false;
    3055             : 
    3056           0 :     roleid = GetUserId();
    3057           0 :     mode = convert_database_priv_string(priv_type_text);
    3058             : 
    3059           0 :     aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
    3060             :                                     roleid, mode,
    3061             :                                     &is_missing);
    3062             : 
    3063           0 :     if (is_missing)
    3064           0 :         PG_RETURN_NULL();
    3065             : 
    3066           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3067             : }
    3068             : 
    3069             : /*
    3070             :  * has_database_privilege_id_name
    3071             :  *      Check user privileges on a database given
    3072             :  *      roleid, text databasename, and text priv name.
    3073             :  */
    3074             : Datum
    3075           0 : has_database_privilege_id_name(PG_FUNCTION_ARGS)
    3076             : {
    3077           0 :     Oid         roleid = PG_GETARG_OID(0);
    3078           0 :     text       *databasename = PG_GETARG_TEXT_PP(1);
    3079           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3080             :     Oid         databaseoid;
    3081             :     AclMode     mode;
    3082             :     AclResult   aclresult;
    3083             : 
    3084           0 :     databaseoid = convert_database_name(databasename);
    3085           0 :     mode = convert_database_priv_string(priv_type_text);
    3086             : 
    3087           0 :     aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
    3088             : 
    3089           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3090             : }
    3091             : 
    3092             : /*
    3093             :  * has_database_privilege_id_id
    3094             :  *      Check user privileges on a database given
    3095             :  *      roleid, database oid, and text priv name.
    3096             :  */
    3097             : Datum
    3098           0 : has_database_privilege_id_id(PG_FUNCTION_ARGS)
    3099             : {
    3100           0 :     Oid         roleid = PG_GETARG_OID(0);
    3101           0 :     Oid         databaseoid = PG_GETARG_OID(1);
    3102           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3103             :     AclMode     mode;
    3104             :     AclResult   aclresult;
    3105           0 :     bool        is_missing = false;
    3106             : 
    3107           0 :     mode = convert_database_priv_string(priv_type_text);
    3108             : 
    3109           0 :     aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
    3110             :                                     roleid, mode,
    3111             :                                     &is_missing);
    3112             : 
    3113           0 :     if (is_missing)
    3114           0 :         PG_RETURN_NULL();
    3115             : 
    3116           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3117             : }
    3118             : 
    3119             : /*
    3120             :  *      Support routines for has_database_privilege family.
    3121             :  */
    3122             : 
    3123             : /*
    3124             :  * Given a database name expressed as a string, look it up and return Oid
    3125             :  */
    3126             : static Oid
    3127           0 : convert_database_name(text *databasename)
    3128             : {
    3129           0 :     char       *dbname = text_to_cstring(databasename);
    3130             : 
    3131           0 :     return get_database_oid(dbname, false);
    3132             : }
    3133             : 
    3134             : /*
    3135             :  * convert_database_priv_string
    3136             :  *      Convert text string to AclMode value.
    3137             :  */
    3138             : static AclMode
    3139           0 : convert_database_priv_string(text *priv_type_text)
    3140             : {
    3141             :     static const priv_map database_priv_map[] = {
    3142             :         {"CREATE", ACL_CREATE},
    3143             :         {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    3144             :         {"TEMPORARY", ACL_CREATE_TEMP},
    3145             :         {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
    3146             :         {"TEMP", ACL_CREATE_TEMP},
    3147             :         {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
    3148             :         {"CONNECT", ACL_CONNECT},
    3149             :         {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
    3150             :         {NULL, 0}
    3151             :     };
    3152             : 
    3153           0 :     return convert_any_priv_string(priv_type_text, database_priv_map);
    3154             : }
    3155             : 
    3156             : 
    3157             : /*
    3158             :  * has_foreign_data_wrapper_privilege variants
    3159             :  *      These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
    3160             :  *      They take various combinations of foreign-data wrapper name,
    3161             :  *      fdw OID, user name, user OID, or implicit user = current_user.
    3162             :  *
    3163             :  *      The result is a boolean value: true if user has the indicated
    3164             :  *      privilege, false if not.
    3165             :  */
    3166             : 
    3167             : /*
    3168             :  * has_foreign_data_wrapper_privilege_name_name
    3169             :  *      Check user privileges on a foreign-data wrapper given
    3170             :  *      name username, text fdwname, and text priv name.
    3171             :  */
    3172             : Datum
    3173          12 : has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
    3174             : {
    3175          12 :     Name        username = PG_GETARG_NAME(0);
    3176          12 :     text       *fdwname = PG_GETARG_TEXT_PP(1);
    3177          12 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3178             :     Oid         roleid;
    3179             :     Oid         fdwid;
    3180             :     AclMode     mode;
    3181             :     AclResult   aclresult;
    3182             : 
    3183          12 :     roleid = get_role_oid_or_public(NameStr(*username));
    3184          12 :     fdwid = convert_foreign_data_wrapper_name(fdwname);
    3185          12 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3186             : 
    3187          12 :     aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
    3188             : 
    3189          12 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3190             : }
    3191             : 
    3192             : /*
    3193             :  * has_foreign_data_wrapper_privilege_name
    3194             :  *      Check user privileges on a foreign-data wrapper given
    3195             :  *      text fdwname and text priv name.
    3196             :  *      current_user is assumed
    3197             :  */
    3198             : Datum
    3199           6 : has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
    3200             : {
    3201           6 :     text       *fdwname = PG_GETARG_TEXT_PP(0);
    3202           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3203             :     Oid         roleid;
    3204             :     Oid         fdwid;
    3205             :     AclMode     mode;
    3206             :     AclResult   aclresult;
    3207             : 
    3208           6 :     roleid = GetUserId();
    3209           6 :     fdwid = convert_foreign_data_wrapper_name(fdwname);
    3210           6 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3211             : 
    3212           6 :     aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
    3213             : 
    3214           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3215             : }
    3216             : 
    3217             : /*
    3218             :  * has_foreign_data_wrapper_privilege_name_id
    3219             :  *      Check user privileges on a foreign-data wrapper given
    3220             :  *      name usename, foreign-data wrapper oid, and text priv name.
    3221             :  */
    3222             : Datum
    3223           6 : has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
    3224             : {
    3225           6 :     Name        username = PG_GETARG_NAME(0);
    3226           6 :     Oid         fdwid = PG_GETARG_OID(1);
    3227           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3228             :     Oid         roleid;
    3229             :     AclMode     mode;
    3230             :     AclResult   aclresult;
    3231           6 :     bool        is_missing = false;
    3232             : 
    3233           6 :     roleid = get_role_oid_or_public(NameStr(*username));
    3234           6 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3235             : 
    3236           6 :     aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
    3237             :                                     roleid, mode,
    3238             :                                     &is_missing);
    3239             : 
    3240           6 :     if (is_missing)
    3241           0 :         PG_RETURN_NULL();
    3242             : 
    3243           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3244             : }
    3245             : 
    3246             : /*
    3247             :  * has_foreign_data_wrapper_privilege_id
    3248             :  *      Check user privileges on a foreign-data wrapper given
    3249             :  *      foreign-data wrapper oid, and text priv name.
    3250             :  *      current_user is assumed
    3251             :  */
    3252             : Datum
    3253           6 : has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
    3254             : {
    3255           6 :     Oid         fdwid = PG_GETARG_OID(0);
    3256           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3257             :     Oid         roleid;
    3258             :     AclMode     mode;
    3259             :     AclResult   aclresult;
    3260           6 :     bool        is_missing = false;
    3261             : 
    3262           6 :     roleid = GetUserId();
    3263           6 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3264             : 
    3265           6 :     aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
    3266             :                                     roleid, mode,
    3267             :                                     &is_missing);
    3268             : 
    3269           6 :     if (is_missing)
    3270           0 :         PG_RETURN_NULL();
    3271             : 
    3272           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3273             : }
    3274             : 
    3275             : /*
    3276             :  * has_foreign_data_wrapper_privilege_id_name
    3277             :  *      Check user privileges on a foreign-data wrapper given
    3278             :  *      roleid, text fdwname, and text priv name.
    3279             :  */
    3280             : Datum
    3281           6 : has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
    3282             : {
    3283           6 :     Oid         roleid = PG_GETARG_OID(0);
    3284           6 :     text       *fdwname = PG_GETARG_TEXT_PP(1);
    3285           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3286             :     Oid         fdwid;
    3287             :     AclMode     mode;
    3288             :     AclResult   aclresult;
    3289             : 
    3290           6 :     fdwid = convert_foreign_data_wrapper_name(fdwname);
    3291           6 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3292             : 
    3293           6 :     aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
    3294             : 
    3295           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3296             : }
    3297             : 
    3298             : /*
    3299             :  * has_foreign_data_wrapper_privilege_id_id
    3300             :  *      Check user privileges on a foreign-data wrapper given
    3301             :  *      roleid, fdw oid, and text priv name.
    3302             :  */
    3303             : Datum
    3304           6 : has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
    3305             : {
    3306           6 :     Oid         roleid = PG_GETARG_OID(0);
    3307           6 :     Oid         fdwid = PG_GETARG_OID(1);
    3308           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3309             :     AclMode     mode;
    3310             :     AclResult   aclresult;
    3311           6 :     bool        is_missing = false;
    3312             : 
    3313           6 :     mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
    3314             : 
    3315           6 :     aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
    3316             :                                     roleid, mode,
    3317             :                                     &is_missing);
    3318             : 
    3319           6 :     if (is_missing)
    3320           0 :         PG_RETURN_NULL();
    3321             : 
    3322           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3323             : }
    3324             : 
    3325             : /*
    3326             :  *      Support routines for has_foreign_data_wrapper_privilege family.
    3327             :  */
    3328             : 
    3329             : /*
    3330             :  * Given a FDW name expressed as a string, look it up and return Oid
    3331             :  */
    3332             : static Oid
    3333          24 : convert_foreign_data_wrapper_name(text *fdwname)
    3334             : {
    3335          24 :     char       *fdwstr = text_to_cstring(fdwname);
    3336             : 
    3337          24 :     return get_foreign_data_wrapper_oid(fdwstr, false);
    3338             : }
    3339             : 
    3340             : /*
    3341             :  * convert_foreign_data_wrapper_priv_string
    3342             :  *      Convert text string to AclMode value.
    3343             :  */
    3344             : static AclMode
    3345          42 : convert_foreign_data_wrapper_priv_string(text *priv_type_text)
    3346             : {
    3347             :     static const priv_map foreign_data_wrapper_priv_map[] = {
    3348             :         {"USAGE", ACL_USAGE},
    3349             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    3350             :         {NULL, 0}
    3351             :     };
    3352             : 
    3353          42 :     return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
    3354             : }
    3355             : 
    3356             : 
    3357             : /*
    3358             :  * has_function_privilege variants
    3359             :  *      These are all named "has_function_privilege" at the SQL level.
    3360             :  *      They take various combinations of function name, function OID,
    3361             :  *      user name, user OID, or implicit user = current_user.
    3362             :  *
    3363             :  *      The result is a boolean value: true if user has the indicated
    3364             :  *      privilege, false if not, or NULL if object doesn't exist.
    3365             :  */
    3366             : 
    3367             : /*
    3368             :  * has_function_privilege_name_name
    3369             :  *      Check user privileges on a function given
    3370             :  *      name username, text functionname, and text priv name.
    3371             :  */
    3372             : Datum
    3373         180 : has_function_privilege_name_name(PG_FUNCTION_ARGS)
    3374             : {
    3375         180 :     Name        username = PG_GETARG_NAME(0);
    3376         180 :     text       *functionname = PG_GETARG_TEXT_PP(1);
    3377         180 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3378             :     Oid         roleid;
    3379             :     Oid         functionoid;
    3380             :     AclMode     mode;
    3381             :     AclResult   aclresult;
    3382             : 
    3383         180 :     roleid = get_role_oid_or_public(NameStr(*username));
    3384         180 :     functionoid = convert_function_name(functionname);
    3385         180 :     mode = convert_function_priv_string(priv_type_text);
    3386             : 
    3387         180 :     aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
    3388             : 
    3389         180 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3390             : }
    3391             : 
    3392             : /*
    3393             :  * has_function_privilege_name
    3394             :  *      Check user privileges on a function given
    3395             :  *      text functionname and text priv name.
    3396             :  *      current_user is assumed
    3397             :  */
    3398             : Datum
    3399           0 : has_function_privilege_name(PG_FUNCTION_ARGS)
    3400             : {
    3401           0 :     text       *functionname = PG_GETARG_TEXT_PP(0);
    3402           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3403             :     Oid         roleid;
    3404             :     Oid         functionoid;
    3405             :     AclMode     mode;
    3406             :     AclResult   aclresult;
    3407             : 
    3408           0 :     roleid = GetUserId();
    3409           0 :     functionoid = convert_function_name(functionname);
    3410           0 :     mode = convert_function_priv_string(priv_type_text);
    3411             : 
    3412           0 :     aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
    3413             : 
    3414           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3415             : }
    3416             : 
    3417             : /*
    3418             :  * has_function_privilege_name_id
    3419             :  *      Check user privileges on a function given
    3420             :  *      name usename, function oid, and text priv name.
    3421             :  */
    3422             : Datum
    3423           0 : has_function_privilege_name_id(PG_FUNCTION_ARGS)
    3424             : {
    3425           0 :     Name        username = PG_GETARG_NAME(0);
    3426           0 :     Oid         functionoid = PG_GETARG_OID(1);
    3427           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3428             :     Oid         roleid;
    3429             :     AclMode     mode;
    3430             :     AclResult   aclresult;
    3431           0 :     bool        is_missing = false;
    3432             : 
    3433           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    3434           0 :     mode = convert_function_priv_string(priv_type_text);
    3435             : 
    3436           0 :     aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
    3437             :                                     roleid, mode,
    3438             :                                     &is_missing);
    3439             : 
    3440           0 :     if (is_missing)
    3441           0 :         PG_RETURN_NULL();
    3442             : 
    3443           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3444             : }
    3445             : 
    3446             : /*
    3447             :  * has_function_privilege_id
    3448             :  *      Check user privileges on a function given
    3449             :  *      function oid, and text priv name.
    3450             :  *      current_user is assumed
    3451             :  */
    3452             : Datum
    3453           0 : has_function_privilege_id(PG_FUNCTION_ARGS)
    3454             : {
    3455           0 :     Oid         functionoid = PG_GETARG_OID(0);
    3456           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3457             :     Oid         roleid;
    3458             :     AclMode     mode;
    3459             :     AclResult   aclresult;
    3460           0 :     bool        is_missing = false;
    3461             : 
    3462           0 :     roleid = GetUserId();
    3463           0 :     mode = convert_function_priv_string(priv_type_text);
    3464             : 
    3465           0 :     aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
    3466             :                                     roleid, mode,
    3467             :                                     &is_missing);
    3468             : 
    3469           0 :     if (is_missing)
    3470           0 :         PG_RETURN_NULL();
    3471             : 
    3472           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3473             : }
    3474             : 
    3475             : /*
    3476             :  * has_function_privilege_id_name
    3477             :  *      Check user privileges on a function given
    3478             :  *      roleid, text functionname, and text priv name.
    3479             :  */
    3480             : Datum
    3481           0 : has_function_privilege_id_name(PG_FUNCTION_ARGS)
    3482             : {
    3483           0 :     Oid         roleid = PG_GETARG_OID(0);
    3484           0 :     text       *functionname = PG_GETARG_TEXT_PP(1);
    3485           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3486             :     Oid         functionoid;
    3487             :     AclMode     mode;
    3488             :     AclResult   aclresult;
    3489             : 
    3490           0 :     functionoid = convert_function_name(functionname);
    3491           0 :     mode = convert_function_priv_string(priv_type_text);
    3492             : 
    3493           0 :     aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
    3494             : 
    3495           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3496             : }
    3497             : 
    3498             : /*
    3499             :  * has_function_privilege_id_id
    3500             :  *      Check user privileges on a function given
    3501             :  *      roleid, function oid, and text priv name.
    3502             :  */
    3503             : Datum
    3504           0 : has_function_privilege_id_id(PG_FUNCTION_ARGS)
    3505             : {
    3506           0 :     Oid         roleid = PG_GETARG_OID(0);
    3507           0 :     Oid         functionoid = PG_GETARG_OID(1);
    3508           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3509             :     AclMode     mode;
    3510             :     AclResult   aclresult;
    3511           0 :     bool        is_missing = false;
    3512             : 
    3513           0 :     mode = convert_function_priv_string(priv_type_text);
    3514             : 
    3515           0 :     aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
    3516             :                                     roleid, mode,
    3517             :                                     &is_missing);
    3518             : 
    3519           0 :     if (is_missing)
    3520           0 :         PG_RETURN_NULL();
    3521             : 
    3522           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3523             : }
    3524             : 
    3525             : /*
    3526             :  *      Support routines for has_function_privilege family.
    3527             :  */
    3528             : 
    3529             : /*
    3530             :  * Given a function name expressed as a string, look it up and return Oid
    3531             :  */
    3532             : static Oid
    3533         180 : convert_function_name(text *functionname)
    3534             : {
    3535         180 :     char       *funcname = text_to_cstring(functionname);
    3536             :     Oid         oid;
    3537             : 
    3538         180 :     oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
    3539             :                                                CStringGetDatum(funcname)));
    3540             : 
    3541         180 :     if (!OidIsValid(oid))
    3542           0 :         ereport(ERROR,
    3543             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3544             :                  errmsg("function \"%s\" does not exist", funcname)));
    3545             : 
    3546         180 :     return oid;
    3547             : }
    3548             : 
    3549             : /*
    3550             :  * convert_function_priv_string
    3551             :  *      Convert text string to AclMode value.
    3552             :  */
    3553             : static AclMode
    3554         180 : convert_function_priv_string(text *priv_type_text)
    3555             : {
    3556             :     static const priv_map function_priv_map[] = {
    3557             :         {"EXECUTE", ACL_EXECUTE},
    3558             :         {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
    3559             :         {NULL, 0}
    3560             :     };
    3561             : 
    3562         180 :     return convert_any_priv_string(priv_type_text, function_priv_map);
    3563             : }
    3564             : 
    3565             : 
    3566             : /*
    3567             :  * has_language_privilege variants
    3568             :  *      These are all named "has_language_privilege" at the SQL level.
    3569             :  *      They take various combinations of language name, language OID,
    3570             :  *      user name, user OID, or implicit user = current_user.
    3571             :  *
    3572             :  *      The result is a boolean value: true if user has the indicated
    3573             :  *      privilege, false if not, or NULL if object doesn't exist.
    3574             :  */
    3575             : 
    3576             : /*
    3577             :  * has_language_privilege_name_name
    3578             :  *      Check user privileges on a language given
    3579             :  *      name username, text languagename, and text priv name.
    3580             :  */
    3581             : Datum
    3582           0 : has_language_privilege_name_name(PG_FUNCTION_ARGS)
    3583             : {
    3584           0 :     Name        username = PG_GETARG_NAME(0);
    3585           0 :     text       *languagename = PG_GETARG_TEXT_PP(1);
    3586           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3587             :     Oid         roleid;
    3588             :     Oid         languageoid;
    3589             :     AclMode     mode;
    3590             :     AclResult   aclresult;
    3591             : 
    3592           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    3593           0 :     languageoid = convert_language_name(languagename);
    3594           0 :     mode = convert_language_priv_string(priv_type_text);
    3595             : 
    3596           0 :     aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
    3597             : 
    3598           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3599             : }
    3600             : 
    3601             : /*
    3602             :  * has_language_privilege_name
    3603             :  *      Check user privileges on a language given
    3604             :  *      text languagename and text priv name.
    3605             :  *      current_user is assumed
    3606             :  */
    3607             : Datum
    3608           0 : has_language_privilege_name(PG_FUNCTION_ARGS)
    3609             : {
    3610           0 :     text       *languagename = PG_GETARG_TEXT_PP(0);
    3611           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3612             :     Oid         roleid;
    3613             :     Oid         languageoid;
    3614             :     AclMode     mode;
    3615             :     AclResult   aclresult;
    3616             : 
    3617           0 :     roleid = GetUserId();
    3618           0 :     languageoid = convert_language_name(languagename);
    3619           0 :     mode = convert_language_priv_string(priv_type_text);
    3620             : 
    3621           0 :     aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
    3622             : 
    3623           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3624             : }
    3625             : 
    3626             : /*
    3627             :  * has_language_privilege_name_id
    3628             :  *      Check user privileges on a language given
    3629             :  *      name usename, language oid, and text priv name.
    3630             :  */
    3631             : Datum
    3632           0 : has_language_privilege_name_id(PG_FUNCTION_ARGS)
    3633             : {
    3634           0 :     Name        username = PG_GETARG_NAME(0);
    3635           0 :     Oid         languageoid = PG_GETARG_OID(1);
    3636           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3637             :     Oid         roleid;
    3638             :     AclMode     mode;
    3639             :     AclResult   aclresult;
    3640           0 :     bool        is_missing = false;
    3641             : 
    3642           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    3643           0 :     mode = convert_language_priv_string(priv_type_text);
    3644             : 
    3645           0 :     aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
    3646             :                                     roleid, mode,
    3647             :                                     &is_missing);
    3648             : 
    3649           0 :     if (is_missing)
    3650           0 :         PG_RETURN_NULL();
    3651             : 
    3652           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3653             : }
    3654             : 
    3655             : /*
    3656             :  * has_language_privilege_id
    3657             :  *      Check user privileges on a language given
    3658             :  *      language oid, and text priv name.
    3659             :  *      current_user is assumed
    3660             :  */
    3661             : Datum
    3662           0 : has_language_privilege_id(PG_FUNCTION_ARGS)
    3663             : {
    3664           0 :     Oid         languageoid = PG_GETARG_OID(0);
    3665           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3666             :     Oid         roleid;
    3667             :     AclMode     mode;
    3668             :     AclResult   aclresult;
    3669           0 :     bool        is_missing = false;
    3670             : 
    3671           0 :     roleid = GetUserId();
    3672           0 :     mode = convert_language_priv_string(priv_type_text);
    3673             : 
    3674           0 :     aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
    3675             :                                     roleid, mode,
    3676             :                                     &is_missing);
    3677             : 
    3678           0 :     if (is_missing)
    3679           0 :         PG_RETURN_NULL();
    3680             : 
    3681           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3682             : }
    3683             : 
    3684             : /*
    3685             :  * has_language_privilege_id_name
    3686             :  *      Check user privileges on a language given
    3687             :  *      roleid, text languagename, and text priv name.
    3688             :  */
    3689             : Datum
    3690           0 : has_language_privilege_id_name(PG_FUNCTION_ARGS)
    3691             : {
    3692           0 :     Oid         roleid = PG_GETARG_OID(0);
    3693           0 :     text       *languagename = PG_GETARG_TEXT_PP(1);
    3694           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3695             :     Oid         languageoid;
    3696             :     AclMode     mode;
    3697             :     AclResult   aclresult;
    3698             : 
    3699           0 :     languageoid = convert_language_name(languagename);
    3700           0 :     mode = convert_language_priv_string(priv_type_text);
    3701             : 
    3702           0 :     aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
    3703             : 
    3704           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3705             : }
    3706             : 
    3707             : /*
    3708             :  * has_language_privilege_id_id
    3709             :  *      Check user privileges on a language given
    3710             :  *      roleid, language oid, and text priv name.
    3711             :  */
    3712             : Datum
    3713           0 : has_language_privilege_id_id(PG_FUNCTION_ARGS)
    3714             : {
    3715           0 :     Oid         roleid = PG_GETARG_OID(0);
    3716           0 :     Oid         languageoid = PG_GETARG_OID(1);
    3717           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3718             :     AclMode     mode;
    3719             :     AclResult   aclresult;
    3720           0 :     bool        is_missing = false;
    3721             : 
    3722           0 :     mode = convert_language_priv_string(priv_type_text);
    3723             : 
    3724           0 :     aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
    3725             :                                     roleid, mode,
    3726             :                                     &is_missing);
    3727             : 
    3728           0 :     if (is_missing)
    3729           0 :         PG_RETURN_NULL();
    3730             : 
    3731           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3732             : }
    3733             : 
    3734             : /*
    3735             :  *      Support routines for has_language_privilege family.
    3736             :  */
    3737             : 
    3738             : /*
    3739             :  * Given a language name expressed as a string, look it up and return Oid
    3740             :  */
    3741             : static Oid
    3742           0 : convert_language_name(text *languagename)
    3743             : {
    3744           0 :     char       *langname = text_to_cstring(languagename);
    3745             : 
    3746           0 :     return get_language_oid(langname, false);
    3747             : }
    3748             : 
    3749             : /*
    3750             :  * convert_language_priv_string
    3751             :  *      Convert text string to AclMode value.
    3752             :  */
    3753             : static AclMode
    3754           0 : convert_language_priv_string(text *priv_type_text)
    3755             : {
    3756             :     static const priv_map language_priv_map[] = {
    3757             :         {"USAGE", ACL_USAGE},
    3758             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    3759             :         {NULL, 0}
    3760             :     };
    3761             : 
    3762           0 :     return convert_any_priv_string(priv_type_text, language_priv_map);
    3763             : }
    3764             : 
    3765             : 
    3766             : /*
    3767             :  * has_schema_privilege variants
    3768             :  *      These are all named "has_schema_privilege" at the SQL level.
    3769             :  *      They take various combinations of schema name, schema OID,
    3770             :  *      user name, user OID, or implicit user = current_user.
    3771             :  *
    3772             :  *      The result is a boolean value: true if user has the indicated
    3773             :  *      privilege, false if not, or NULL if object doesn't exist.
    3774             :  */
    3775             : 
    3776             : /*
    3777             :  * has_schema_privilege_name_name
    3778             :  *      Check user privileges on a schema given
    3779             :  *      name username, text schemaname, and text priv name.
    3780             :  */
    3781             : Datum
    3782          54 : has_schema_privilege_name_name(PG_FUNCTION_ARGS)
    3783             : {
    3784          54 :     Name        username = PG_GETARG_NAME(0);
    3785          54 :     text       *schemaname = PG_GETARG_TEXT_PP(1);
    3786          54 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3787             :     Oid         roleid;
    3788             :     Oid         schemaoid;
    3789             :     AclMode     mode;
    3790             :     AclResult   aclresult;
    3791             : 
    3792          54 :     roleid = get_role_oid_or_public(NameStr(*username));
    3793          54 :     schemaoid = convert_schema_name(schemaname);
    3794          54 :     mode = convert_schema_priv_string(priv_type_text);
    3795             : 
    3796          54 :     aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
    3797             : 
    3798          54 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3799             : }
    3800             : 
    3801             : /*
    3802             :  * has_schema_privilege_name
    3803             :  *      Check user privileges on a schema given
    3804             :  *      text schemaname and text priv name.
    3805             :  *      current_user is assumed
    3806             :  */
    3807             : Datum
    3808           0 : has_schema_privilege_name(PG_FUNCTION_ARGS)
    3809             : {
    3810           0 :     text       *schemaname = PG_GETARG_TEXT_PP(0);
    3811           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3812             :     Oid         roleid;
    3813             :     Oid         schemaoid;
    3814             :     AclMode     mode;
    3815             :     AclResult   aclresult;
    3816             : 
    3817           0 :     roleid = GetUserId();
    3818           0 :     schemaoid = convert_schema_name(schemaname);
    3819           0 :     mode = convert_schema_priv_string(priv_type_text);
    3820             : 
    3821           0 :     aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
    3822             : 
    3823           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3824             : }
    3825             : 
    3826             : /*
    3827             :  * has_schema_privilege_name_id
    3828             :  *      Check user privileges on a schema given
    3829             :  *      name usename, schema oid, and text priv name.
    3830             :  */
    3831             : Datum
    3832           0 : has_schema_privilege_name_id(PG_FUNCTION_ARGS)
    3833             : {
    3834           0 :     Name        username = PG_GETARG_NAME(0);
    3835           0 :     Oid         schemaoid = PG_GETARG_OID(1);
    3836           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3837             :     Oid         roleid;
    3838             :     AclMode     mode;
    3839             :     AclResult   aclresult;
    3840           0 :     bool        is_missing = false;
    3841             : 
    3842           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    3843           0 :     mode = convert_schema_priv_string(priv_type_text);
    3844             : 
    3845           0 :     aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
    3846             :                                     roleid, mode,
    3847             :                                     &is_missing);
    3848             : 
    3849           0 :     if (is_missing)
    3850           0 :         PG_RETURN_NULL();
    3851             : 
    3852           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3853             : }
    3854             : 
    3855             : /*
    3856             :  * has_schema_privilege_id
    3857             :  *      Check user privileges on a schema given
    3858             :  *      schema oid, and text priv name.
    3859             :  *      current_user is assumed
    3860             :  */
    3861             : Datum
    3862           0 : has_schema_privilege_id(PG_FUNCTION_ARGS)
    3863             : {
    3864           0 :     Oid         schemaoid = PG_GETARG_OID(0);
    3865           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    3866             :     Oid         roleid;
    3867             :     AclMode     mode;
    3868             :     AclResult   aclresult;
    3869           0 :     bool        is_missing = false;
    3870             : 
    3871           0 :     roleid = GetUserId();
    3872           0 :     mode = convert_schema_priv_string(priv_type_text);
    3873             : 
    3874           0 :     aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
    3875             :                                     roleid, mode,
    3876             :                                     &is_missing);
    3877             : 
    3878           0 :     if (is_missing)
    3879           0 :         PG_RETURN_NULL();
    3880             : 
    3881           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3882             : }
    3883             : 
    3884             : /*
    3885             :  * has_schema_privilege_id_name
    3886             :  *      Check user privileges on a schema given
    3887             :  *      roleid, text schemaname, and text priv name.
    3888             :  */
    3889             : Datum
    3890           0 : has_schema_privilege_id_name(PG_FUNCTION_ARGS)
    3891             : {
    3892           0 :     Oid         roleid = PG_GETARG_OID(0);
    3893           0 :     text       *schemaname = PG_GETARG_TEXT_PP(1);
    3894           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3895             :     Oid         schemaoid;
    3896             :     AclMode     mode;
    3897             :     AclResult   aclresult;
    3898             : 
    3899           0 :     schemaoid = convert_schema_name(schemaname);
    3900           0 :     mode = convert_schema_priv_string(priv_type_text);
    3901             : 
    3902           0 :     aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
    3903             : 
    3904           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3905             : }
    3906             : 
    3907             : /*
    3908             :  * has_schema_privilege_id_id
    3909             :  *      Check user privileges on a schema given
    3910             :  *      roleid, schema oid, and text priv name.
    3911             :  */
    3912             : Datum
    3913           0 : has_schema_privilege_id_id(PG_FUNCTION_ARGS)
    3914             : {
    3915           0 :     Oid         roleid = PG_GETARG_OID(0);
    3916           0 :     Oid         schemaoid = PG_GETARG_OID(1);
    3917           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3918             :     AclMode     mode;
    3919             :     AclResult   aclresult;
    3920           0 :     bool        is_missing = false;
    3921             : 
    3922           0 :     mode = convert_schema_priv_string(priv_type_text);
    3923             : 
    3924           0 :     aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
    3925             :                                     roleid, mode,
    3926             :                                     &is_missing);
    3927             : 
    3928           0 :     if (is_missing)
    3929           0 :         PG_RETURN_NULL();
    3930             : 
    3931           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    3932             : }
    3933             : 
    3934             : /*
    3935             :  *      Support routines for has_schema_privilege family.
    3936             :  */
    3937             : 
    3938             : /*
    3939             :  * Given a schema name expressed as a string, look it up and return Oid
    3940             :  */
    3941             : static Oid
    3942          54 : convert_schema_name(text *schemaname)
    3943             : {
    3944          54 :     char       *nspname = text_to_cstring(schemaname);
    3945             : 
    3946          54 :     return get_namespace_oid(nspname, false);
    3947             : }
    3948             : 
    3949             : /*
    3950             :  * convert_schema_priv_string
    3951             :  *      Convert text string to AclMode value.
    3952             :  */
    3953             : static AclMode
    3954          54 : convert_schema_priv_string(text *priv_type_text)
    3955             : {
    3956             :     static const priv_map schema_priv_map[] = {
    3957             :         {"CREATE", ACL_CREATE},
    3958             :         {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    3959             :         {"USAGE", ACL_USAGE},
    3960             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    3961             :         {NULL, 0}
    3962             :     };
    3963             : 
    3964          54 :     return convert_any_priv_string(priv_type_text, schema_priv_map);
    3965             : }
    3966             : 
    3967             : 
    3968             : /*
    3969             :  * has_server_privilege variants
    3970             :  *      These are all named "has_server_privilege" at the SQL level.
    3971             :  *      They take various combinations of foreign server name,
    3972             :  *      server OID, user name, user OID, or implicit user = current_user.
    3973             :  *
    3974             :  *      The result is a boolean value: true if user has the indicated
    3975             :  *      privilege, false if not.
    3976             :  */
    3977             : 
    3978             : /*
    3979             :  * has_server_privilege_name_name
    3980             :  *      Check user privileges on a foreign server given
    3981             :  *      name username, text servername, and text priv name.
    3982             :  */
    3983             : Datum
    3984          12 : has_server_privilege_name_name(PG_FUNCTION_ARGS)
    3985             : {
    3986          12 :     Name        username = PG_GETARG_NAME(0);
    3987          12 :     text       *servername = PG_GETARG_TEXT_PP(1);
    3988          12 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    3989             :     Oid         roleid;
    3990             :     Oid         serverid;
    3991             :     AclMode     mode;
    3992             :     AclResult   aclresult;
    3993             : 
    3994          12 :     roleid = get_role_oid_or_public(NameStr(*username));
    3995          12 :     serverid = convert_server_name(servername);
    3996          12 :     mode = convert_server_priv_string(priv_type_text);
    3997             : 
    3998          12 :     aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
    3999             : 
    4000          12 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4001             : }
    4002             : 
    4003             : /*
    4004             :  * has_server_privilege_name
    4005             :  *      Check user privileges on a foreign server given
    4006             :  *      text servername and text priv name.
    4007             :  *      current_user is assumed
    4008             :  */
    4009             : Datum
    4010           6 : has_server_privilege_name(PG_FUNCTION_ARGS)
    4011             : {
    4012           6 :     text       *servername = PG_GETARG_TEXT_PP(0);
    4013           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4014             :     Oid         roleid;
    4015             :     Oid         serverid;
    4016             :     AclMode     mode;
    4017             :     AclResult   aclresult;
    4018             : 
    4019           6 :     roleid = GetUserId();
    4020           6 :     serverid = convert_server_name(servername);
    4021           6 :     mode = convert_server_priv_string(priv_type_text);
    4022             : 
    4023           6 :     aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
    4024             : 
    4025           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4026             : }
    4027             : 
    4028             : /*
    4029             :  * has_server_privilege_name_id
    4030             :  *      Check user privileges on a foreign server given
    4031             :  *      name usename, foreign server oid, and text priv name.
    4032             :  */
    4033             : Datum
    4034           6 : has_server_privilege_name_id(PG_FUNCTION_ARGS)
    4035             : {
    4036           6 :     Name        username = PG_GETARG_NAME(0);
    4037           6 :     Oid         serverid = PG_GETARG_OID(1);
    4038           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4039             :     Oid         roleid;
    4040             :     AclMode     mode;
    4041             :     AclResult   aclresult;
    4042           6 :     bool        is_missing = false;
    4043             : 
    4044           6 :     roleid = get_role_oid_or_public(NameStr(*username));
    4045           6 :     mode = convert_server_priv_string(priv_type_text);
    4046             : 
    4047           6 :     aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
    4048             :                                     roleid, mode,
    4049             :                                     &is_missing);
    4050             : 
    4051           6 :     if (is_missing)
    4052           0 :         PG_RETURN_NULL();
    4053             : 
    4054           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4055             : }
    4056             : 
    4057             : /*
    4058             :  * has_server_privilege_id
    4059             :  *      Check user privileges on a foreign server given
    4060             :  *      server oid, and text priv name.
    4061             :  *      current_user is assumed
    4062             :  */
    4063             : Datum
    4064          78 : has_server_privilege_id(PG_FUNCTION_ARGS)
    4065             : {
    4066          78 :     Oid         serverid = PG_GETARG_OID(0);
    4067          78 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4068             :     Oid         roleid;
    4069             :     AclMode     mode;
    4070             :     AclResult   aclresult;
    4071          78 :     bool        is_missing = false;
    4072             : 
    4073          78 :     roleid = GetUserId();
    4074          78 :     mode = convert_server_priv_string(priv_type_text);
    4075             : 
    4076          78 :     aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
    4077             :                                     roleid, mode,
    4078             :                                     &is_missing);
    4079             : 
    4080          78 :     if (is_missing)
    4081           0 :         PG_RETURN_NULL();
    4082             : 
    4083          78 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4084             : }
    4085             : 
    4086             : /*
    4087             :  * has_server_privilege_id_name
    4088             :  *      Check user privileges on a foreign server given
    4089             :  *      roleid, text servername, and text priv name.
    4090             :  */
    4091             : Datum
    4092           6 : has_server_privilege_id_name(PG_FUNCTION_ARGS)
    4093             : {
    4094           6 :     Oid         roleid = PG_GETARG_OID(0);
    4095           6 :     text       *servername = PG_GETARG_TEXT_PP(1);
    4096           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4097             :     Oid         serverid;
    4098             :     AclMode     mode;
    4099             :     AclResult   aclresult;
    4100             : 
    4101           6 :     serverid = convert_server_name(servername);
    4102           6 :     mode = convert_server_priv_string(priv_type_text);
    4103             : 
    4104           6 :     aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
    4105             : 
    4106           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4107             : }
    4108             : 
    4109             : /*
    4110             :  * has_server_privilege_id_id
    4111             :  *      Check user privileges on a foreign server given
    4112             :  *      roleid, server oid, and text priv name.
    4113             :  */
    4114             : Datum
    4115           6 : has_server_privilege_id_id(PG_FUNCTION_ARGS)
    4116             : {
    4117           6 :     Oid         roleid = PG_GETARG_OID(0);
    4118           6 :     Oid         serverid = PG_GETARG_OID(1);
    4119           6 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4120             :     AclMode     mode;
    4121             :     AclResult   aclresult;
    4122           6 :     bool        is_missing = false;
    4123             : 
    4124           6 :     mode = convert_server_priv_string(priv_type_text);
    4125             : 
    4126           6 :     aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
    4127             :                                     roleid, mode,
    4128             :                                     &is_missing);
    4129             : 
    4130           6 :     if (is_missing)
    4131           0 :         PG_RETURN_NULL();
    4132             : 
    4133           6 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4134             : }
    4135             : 
    4136             : /*
    4137             :  *      Support routines for has_server_privilege family.
    4138             :  */
    4139             : 
    4140             : /*
    4141             :  * Given a server name expressed as a string, look it up and return Oid
    4142             :  */
    4143             : static Oid
    4144          24 : convert_server_name(text *servername)
    4145             : {
    4146          24 :     char       *serverstr = text_to_cstring(servername);
    4147             : 
    4148          24 :     return get_foreign_server_oid(serverstr, false);
    4149             : }
    4150             : 
    4151             : /*
    4152             :  * convert_server_priv_string
    4153             :  *      Convert text string to AclMode value.
    4154             :  */
    4155             : static AclMode
    4156         114 : convert_server_priv_string(text *priv_type_text)
    4157             : {
    4158             :     static const priv_map server_priv_map[] = {
    4159             :         {"USAGE", ACL_USAGE},
    4160             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    4161             :         {NULL, 0}
    4162             :     };
    4163             : 
    4164         114 :     return convert_any_priv_string(priv_type_text, server_priv_map);
    4165             : }
    4166             : 
    4167             : 
    4168             : /*
    4169             :  * has_tablespace_privilege variants
    4170             :  *      These are all named "has_tablespace_privilege" at the SQL level.
    4171             :  *      They take various combinations of tablespace name, tablespace OID,
    4172             :  *      user name, user OID, or implicit user = current_user.
    4173             :  *
    4174             :  *      The result is a boolean value: true if user has the indicated
    4175             :  *      privilege, false if not.
    4176             :  */
    4177             : 
    4178             : /*
    4179             :  * has_tablespace_privilege_name_name
    4180             :  *      Check user privileges on a tablespace given
    4181             :  *      name username, text tablespacename, and text priv name.
    4182             :  */
    4183             : Datum
    4184           0 : has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
    4185             : {
    4186           0 :     Name        username = PG_GETARG_NAME(0);
    4187           0 :     text       *tablespacename = PG_GETARG_TEXT_PP(1);
    4188           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4189             :     Oid         roleid;
    4190             :     Oid         tablespaceoid;
    4191             :     AclMode     mode;
    4192             :     AclResult   aclresult;
    4193             : 
    4194           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    4195           0 :     tablespaceoid = convert_tablespace_name(tablespacename);
    4196           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4197             : 
    4198           0 :     aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
    4199             : 
    4200           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4201             : }
    4202             : 
    4203             : /*
    4204             :  * has_tablespace_privilege_name
    4205             :  *      Check user privileges on a tablespace given
    4206             :  *      text tablespacename and text priv name.
    4207             :  *      current_user is assumed
    4208             :  */
    4209             : Datum
    4210           0 : has_tablespace_privilege_name(PG_FUNCTION_ARGS)
    4211             : {
    4212           0 :     text       *tablespacename = PG_GETARG_TEXT_PP(0);
    4213           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4214             :     Oid         roleid;
    4215             :     Oid         tablespaceoid;
    4216             :     AclMode     mode;
    4217             :     AclResult   aclresult;
    4218             : 
    4219           0 :     roleid = GetUserId();
    4220           0 :     tablespaceoid = convert_tablespace_name(tablespacename);
    4221           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4222             : 
    4223           0 :     aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
    4224             : 
    4225           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4226             : }
    4227             : 
    4228             : /*
    4229             :  * has_tablespace_privilege_name_id
    4230             :  *      Check user privileges on a tablespace given
    4231             :  *      name usename, tablespace oid, and text priv name.
    4232             :  */
    4233             : Datum
    4234           0 : has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
    4235             : {
    4236           0 :     Name        username = PG_GETARG_NAME(0);
    4237           0 :     Oid         tablespaceoid = PG_GETARG_OID(1);
    4238           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4239             :     Oid         roleid;
    4240             :     AclMode     mode;
    4241             :     AclResult   aclresult;
    4242           0 :     bool        is_missing = false;
    4243             : 
    4244           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    4245           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4246             : 
    4247           0 :     aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
    4248             :                                     roleid, mode,
    4249             :                                     &is_missing);
    4250             : 
    4251           0 :     if (is_missing)
    4252           0 :         PG_RETURN_NULL();
    4253             : 
    4254           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4255             : }
    4256             : 
    4257             : /*
    4258             :  * has_tablespace_privilege_id
    4259             :  *      Check user privileges on a tablespace given
    4260             :  *      tablespace oid, and text priv name.
    4261             :  *      current_user is assumed
    4262             :  */
    4263             : Datum
    4264           0 : has_tablespace_privilege_id(PG_FUNCTION_ARGS)
    4265             : {
    4266           0 :     Oid         tablespaceoid = PG_GETARG_OID(0);
    4267           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4268             :     Oid         roleid;
    4269             :     AclMode     mode;
    4270             :     AclResult   aclresult;
    4271           0 :     bool        is_missing = false;
    4272             : 
    4273           0 :     roleid = GetUserId();
    4274           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4275             : 
    4276           0 :     aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
    4277             :                                     roleid, mode,
    4278             :                                     &is_missing);
    4279             : 
    4280           0 :     if (is_missing)
    4281           0 :         PG_RETURN_NULL();
    4282             : 
    4283           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4284             : }
    4285             : 
    4286             : /*
    4287             :  * has_tablespace_privilege_id_name
    4288             :  *      Check user privileges on a tablespace given
    4289             :  *      roleid, text tablespacename, and text priv name.
    4290             :  */
    4291             : Datum
    4292           0 : has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
    4293             : {
    4294           0 :     Oid         roleid = PG_GETARG_OID(0);
    4295           0 :     text       *tablespacename = PG_GETARG_TEXT_PP(1);
    4296           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4297             :     Oid         tablespaceoid;
    4298             :     AclMode     mode;
    4299             :     AclResult   aclresult;
    4300             : 
    4301           0 :     tablespaceoid = convert_tablespace_name(tablespacename);
    4302           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4303             : 
    4304           0 :     aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
    4305             : 
    4306           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4307             : }
    4308             : 
    4309             : /*
    4310             :  * has_tablespace_privilege_id_id
    4311             :  *      Check user privileges on a tablespace given
    4312             :  *      roleid, tablespace oid, and text priv name.
    4313             :  */
    4314             : Datum
    4315           0 : has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
    4316             : {
    4317           0 :     Oid         roleid = PG_GETARG_OID(0);
    4318           0 :     Oid         tablespaceoid = PG_GETARG_OID(1);
    4319           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4320             :     AclMode     mode;
    4321             :     AclResult   aclresult;
    4322           0 :     bool        is_missing = false;
    4323             : 
    4324           0 :     mode = convert_tablespace_priv_string(priv_type_text);
    4325             : 
    4326           0 :     aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
    4327             :                                     roleid, mode,
    4328             :                                     &is_missing);
    4329             : 
    4330           0 :     if (is_missing)
    4331           0 :         PG_RETURN_NULL();
    4332             : 
    4333           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4334             : }
    4335             : 
    4336             : /*
    4337             :  *      Support routines for has_tablespace_privilege family.
    4338             :  */
    4339             : 
    4340             : /*
    4341             :  * Given a tablespace name expressed as a string, look it up and return Oid
    4342             :  */
    4343             : static Oid
    4344           0 : convert_tablespace_name(text *tablespacename)
    4345             : {
    4346           0 :     char       *spcname = text_to_cstring(tablespacename);
    4347             : 
    4348           0 :     return get_tablespace_oid(spcname, false);
    4349             : }
    4350             : 
    4351             : /*
    4352             :  * convert_tablespace_priv_string
    4353             :  *      Convert text string to AclMode value.
    4354             :  */
    4355             : static AclMode
    4356           0 : convert_tablespace_priv_string(text *priv_type_text)
    4357             : {
    4358             :     static const priv_map tablespace_priv_map[] = {
    4359             :         {"CREATE", ACL_CREATE},
    4360             :         {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4361             :         {NULL, 0}
    4362             :     };
    4363             : 
    4364           0 :     return convert_any_priv_string(priv_type_text, tablespace_priv_map);
    4365             : }
    4366             : 
    4367             : /*
    4368             :  * has_type_privilege variants
    4369             :  *      These are all named "has_type_privilege" at the SQL level.
    4370             :  *      They take various combinations of type name, type OID,
    4371             :  *      user name, user OID, or implicit user = current_user.
    4372             :  *
    4373             :  *      The result is a boolean value: true if user has the indicated
    4374             :  *      privilege, false if not, or NULL if object doesn't exist.
    4375             :  */
    4376             : 
    4377             : /*
    4378             :  * has_type_privilege_name_name
    4379             :  *      Check user privileges on a type given
    4380             :  *      name username, text typename, and text priv name.
    4381             :  */
    4382             : Datum
    4383          12 : has_type_privilege_name_name(PG_FUNCTION_ARGS)
    4384             : {
    4385          12 :     Name        username = PG_GETARG_NAME(0);
    4386          12 :     text       *typename = PG_GETARG_TEXT_PP(1);
    4387          12 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4388             :     Oid         roleid;
    4389             :     Oid         typeoid;
    4390             :     AclMode     mode;
    4391             :     AclResult   aclresult;
    4392             : 
    4393          12 :     roleid = get_role_oid_or_public(NameStr(*username));
    4394          12 :     typeoid = convert_type_name(typename);
    4395          12 :     mode = convert_type_priv_string(priv_type_text);
    4396             : 
    4397          12 :     aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
    4398             : 
    4399          12 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4400             : }
    4401             : 
    4402             : /*
    4403             :  * has_type_privilege_name
    4404             :  *      Check user privileges on a type given
    4405             :  *      text typename and text priv name.
    4406             :  *      current_user is assumed
    4407             :  */
    4408             : Datum
    4409           0 : has_type_privilege_name(PG_FUNCTION_ARGS)
    4410             : {
    4411           0 :     text       *typename = PG_GETARG_TEXT_PP(0);
    4412           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4413             :     Oid         roleid;
    4414             :     Oid         typeoid;
    4415             :     AclMode     mode;
    4416             :     AclResult   aclresult;
    4417             : 
    4418           0 :     roleid = GetUserId();
    4419           0 :     typeoid = convert_type_name(typename);
    4420           0 :     mode = convert_type_priv_string(priv_type_text);
    4421             : 
    4422           0 :     aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
    4423             : 
    4424           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4425             : }
    4426             : 
    4427             : /*
    4428             :  * has_type_privilege_name_id
    4429             :  *      Check user privileges on a type given
    4430             :  *      name usename, type oid, and text priv name.
    4431             :  */
    4432             : Datum
    4433           0 : has_type_privilege_name_id(PG_FUNCTION_ARGS)
    4434             : {
    4435           0 :     Name        username = PG_GETARG_NAME(0);
    4436           0 :     Oid         typeoid = PG_GETARG_OID(1);
    4437           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4438             :     Oid         roleid;
    4439             :     AclMode     mode;
    4440             :     AclResult   aclresult;
    4441           0 :     bool        is_missing = false;
    4442             : 
    4443           0 :     roleid = get_role_oid_or_public(NameStr(*username));
    4444           0 :     mode = convert_type_priv_string(priv_type_text);
    4445             : 
    4446           0 :     aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
    4447             :                                     roleid, mode,
    4448             :                                     &is_missing);
    4449             : 
    4450           0 :     if (is_missing)
    4451           0 :         PG_RETURN_NULL();
    4452             : 
    4453           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4454             : }
    4455             : 
    4456             : /*
    4457             :  * has_type_privilege_id
    4458             :  *      Check user privileges on a type given
    4459             :  *      type oid, and text priv name.
    4460             :  *      current_user is assumed
    4461             :  */
    4462             : Datum
    4463           0 : has_type_privilege_id(PG_FUNCTION_ARGS)
    4464             : {
    4465           0 :     Oid         typeoid = PG_GETARG_OID(0);
    4466           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4467             :     Oid         roleid;
    4468             :     AclMode     mode;
    4469             :     AclResult   aclresult;
    4470           0 :     bool        is_missing = false;
    4471             : 
    4472           0 :     roleid = GetUserId();
    4473           0 :     mode = convert_type_priv_string(priv_type_text);
    4474             : 
    4475           0 :     aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
    4476             :                                     roleid, mode,
    4477             :                                     &is_missing);
    4478             : 
    4479           0 :     if (is_missing)
    4480           0 :         PG_RETURN_NULL();
    4481             : 
    4482           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4483             : }
    4484             : 
    4485             : /*
    4486             :  * has_type_privilege_id_name
    4487             :  *      Check user privileges on a type given
    4488             :  *      roleid, text typename, and text priv name.
    4489             :  */
    4490             : Datum
    4491           0 : has_type_privilege_id_name(PG_FUNCTION_ARGS)
    4492             : {
    4493           0 :     Oid         roleid = PG_GETARG_OID(0);
    4494           0 :     text       *typename = PG_GETARG_TEXT_PP(1);
    4495           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4496             :     Oid         typeoid;
    4497             :     AclMode     mode;
    4498             :     AclResult   aclresult;
    4499             : 
    4500           0 :     typeoid = convert_type_name(typename);
    4501           0 :     mode = convert_type_priv_string(priv_type_text);
    4502             : 
    4503           0 :     aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
    4504             : 
    4505           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4506             : }
    4507             : 
    4508             : /*
    4509             :  * has_type_privilege_id_id
    4510             :  *      Check user privileges on a type given
    4511             :  *      roleid, type oid, and text priv name.
    4512             :  */
    4513             : Datum
    4514           0 : has_type_privilege_id_id(PG_FUNCTION_ARGS)
    4515             : {
    4516           0 :     Oid         roleid = PG_GETARG_OID(0);
    4517           0 :     Oid         typeoid = PG_GETARG_OID(1);
    4518           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4519             :     AclMode     mode;
    4520             :     AclResult   aclresult;
    4521           0 :     bool        is_missing = false;
    4522             : 
    4523           0 :     mode = convert_type_priv_string(priv_type_text);
    4524             : 
    4525           0 :     aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
    4526             :                                     roleid, mode,
    4527             :                                     &is_missing);
    4528             : 
    4529           0 :     if (is_missing)
    4530           0 :         PG_RETURN_NULL();
    4531             : 
    4532           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4533             : }
    4534             : 
    4535             : /*
    4536             :  *      Support routines for has_type_privilege family.
    4537             :  */
    4538             : 
    4539             : /*
    4540             :  * Given a type name expressed as a string, look it up and return Oid
    4541             :  */
    4542             : static Oid
    4543          12 : convert_type_name(text *typename)
    4544             : {
    4545          12 :     char       *typname = text_to_cstring(typename);
    4546             :     Oid         oid;
    4547             : 
    4548          12 :     oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
    4549             :                                                CStringGetDatum(typname)));
    4550             : 
    4551          12 :     if (!OidIsValid(oid))
    4552           0 :         ereport(ERROR,
    4553             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    4554             :                  errmsg("type \"%s\" does not exist", typname)));
    4555             : 
    4556          12 :     return oid;
    4557             : }
    4558             : 
    4559             : /*
    4560             :  * convert_type_priv_string
    4561             :  *      Convert text string to AclMode value.
    4562             :  */
    4563             : static AclMode
    4564          12 : convert_type_priv_string(text *priv_type_text)
    4565             : {
    4566             :     static const priv_map type_priv_map[] = {
    4567             :         {"USAGE", ACL_USAGE},
    4568             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
    4569             :         {NULL, 0}
    4570             :     };
    4571             : 
    4572          12 :     return convert_any_priv_string(priv_type_text, type_priv_map);
    4573             : }
    4574             : 
    4575             : /*
    4576             :  * has_parameter_privilege variants
    4577             :  *      These are all named "has_parameter_privilege" at the SQL level.
    4578             :  *      They take various combinations of parameter name with
    4579             :  *      user name, user OID, or implicit user = current_user.
    4580             :  *
    4581             :  *      The result is a boolean value: true if user has been granted
    4582             :  *      the indicated privilege or false if not.
    4583             :  */
    4584             : 
    4585             : /*
    4586             :  * has_param_priv_byname
    4587             :  *
    4588             :  *      Helper function to check user privileges on a parameter given the
    4589             :  *      role by Oid, parameter by text name, and privileges as AclMode.
    4590             :  */
    4591             : static bool
    4592          74 : has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
    4593             : {
    4594          74 :     char       *paramstr = text_to_cstring(parameter);
    4595             : 
    4596          74 :     return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
    4597             : }
    4598             : 
    4599             : /*
    4600             :  * has_parameter_privilege_name_name
    4601             :  *      Check user privileges on a parameter given name username, text
    4602             :  *      parameter, and text priv name.
    4603             :  */
    4604             : Datum
    4605          84 : has_parameter_privilege_name_name(PG_FUNCTION_ARGS)
    4606             : {
    4607          84 :     Name        username = PG_GETARG_NAME(0);
    4608          84 :     text       *parameter = PG_GETARG_TEXT_PP(1);
    4609          84 :     AclMode     priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
    4610          70 :     Oid         roleid = get_role_oid_or_public(NameStr(*username));
    4611             : 
    4612          70 :     PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
    4613             : }
    4614             : 
    4615             : /*
    4616             :  * has_parameter_privilege_name
    4617             :  *      Check user privileges on a parameter given text parameter and text priv
    4618             :  *      name.  current_user is assumed
    4619             :  */
    4620             : Datum
    4621           2 : has_parameter_privilege_name(PG_FUNCTION_ARGS)
    4622             : {
    4623           2 :     text       *parameter = PG_GETARG_TEXT_PP(0);
    4624           2 :     AclMode     priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(1));
    4625             : 
    4626           2 :     PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
    4627             : }
    4628             : 
    4629             : /*
    4630             :  * has_parameter_privilege_id_name
    4631             :  *      Check user privileges on a parameter given roleid, text parameter, and
    4632             :  *      text priv name.
    4633             :  */
    4634             : Datum
    4635           2 : has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
    4636             : {
    4637           2 :     Oid         roleid = PG_GETARG_OID(0);
    4638           2 :     text       *parameter = PG_GETARG_TEXT_PP(1);
    4639           2 :     AclMode     priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
    4640             : 
    4641           2 :     PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
    4642             : }
    4643             : 
    4644             : /*
    4645             :  *      Support routines for has_parameter_privilege family.
    4646             :  */
    4647             : 
    4648             : /*
    4649             :  * convert_parameter_priv_string
    4650             :  *      Convert text string to AclMode value.
    4651             :  */
    4652             : static AclMode
    4653          88 : convert_parameter_priv_string(text *priv_text)
    4654             : {
    4655             :     static const priv_map parameter_priv_map[] = {
    4656             :         {"SET", ACL_SET},
    4657             :         {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
    4658             :         {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
    4659             :         {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
    4660             :         {NULL, 0}
    4661             :     };
    4662             : 
    4663          88 :     return convert_any_priv_string(priv_text, parameter_priv_map);
    4664             : }
    4665             : 
    4666             : /*
    4667             :  * pg_has_role variants
    4668             :  *      These are all named "pg_has_role" at the SQL level.
    4669             :  *      They take various combinations of role name, role OID,
    4670             :  *      user name, user OID, or implicit user = current_user.
    4671             :  *
    4672             :  *      The result is a boolean value: true if user has the indicated
    4673             :  *      privilege, false if not.
    4674             :  */
    4675             : 
    4676             : /*
    4677             :  * pg_has_role_name_name
    4678             :  *      Check user privileges on a role given
    4679             :  *      name username, name rolename, and text priv name.
    4680             :  */
    4681             : Datum
    4682          36 : pg_has_role_name_name(PG_FUNCTION_ARGS)
    4683             : {
    4684          36 :     Name        username = PG_GETARG_NAME(0);
    4685          36 :     Name        rolename = PG_GETARG_NAME(1);
    4686          36 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4687             :     Oid         roleid;
    4688             :     Oid         roleoid;
    4689             :     AclMode     mode;
    4690             :     AclResult   aclresult;
    4691             : 
    4692          36 :     roleid = get_role_oid(NameStr(*username), false);
    4693          36 :     roleoid = get_role_oid(NameStr(*rolename), false);
    4694          36 :     mode = convert_role_priv_string(priv_type_text);
    4695             : 
    4696          36 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4697             : 
    4698          36 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4699             : }
    4700             : 
    4701             : /*
    4702             :  * pg_has_role_name
    4703             :  *      Check user privileges on a role given
    4704             :  *      name rolename and text priv name.
    4705             :  *      current_user is assumed
    4706             :  */
    4707             : Datum
    4708          18 : pg_has_role_name(PG_FUNCTION_ARGS)
    4709             : {
    4710          18 :     Name        rolename = PG_GETARG_NAME(0);
    4711          18 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4712             :     Oid         roleid;
    4713             :     Oid         roleoid;
    4714             :     AclMode     mode;
    4715             :     AclResult   aclresult;
    4716             : 
    4717          18 :     roleid = GetUserId();
    4718          18 :     roleoid = get_role_oid(NameStr(*rolename), false);
    4719          18 :     mode = convert_role_priv_string(priv_type_text);
    4720             : 
    4721          18 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4722             : 
    4723          18 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4724             : }
    4725             : 
    4726             : /*
    4727             :  * pg_has_role_name_id
    4728             :  *      Check user privileges on a role given
    4729             :  *      name usename, role oid, and text priv name.
    4730             :  */
    4731             : Datum
    4732           0 : pg_has_role_name_id(PG_FUNCTION_ARGS)
    4733             : {
    4734           0 :     Name        username = PG_GETARG_NAME(0);
    4735           0 :     Oid         roleoid = PG_GETARG_OID(1);
    4736           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4737             :     Oid         roleid;
    4738             :     AclMode     mode;
    4739             :     AclResult   aclresult;
    4740             : 
    4741           0 :     roleid = get_role_oid(NameStr(*username), false);
    4742           0 :     mode = convert_role_priv_string(priv_type_text);
    4743             : 
    4744           0 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4745             : 
    4746           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4747             : }
    4748             : 
    4749             : /*
    4750             :  * pg_has_role_id
    4751             :  *      Check user privileges on a role given
    4752             :  *      role oid, and text priv name.
    4753             :  *      current_user is assumed
    4754             :  */
    4755             : Datum
    4756       92404 : pg_has_role_id(PG_FUNCTION_ARGS)
    4757             : {
    4758       92404 :     Oid         roleoid = PG_GETARG_OID(0);
    4759       92404 :     text       *priv_type_text = PG_GETARG_TEXT_PP(1);
    4760             :     Oid         roleid;
    4761             :     AclMode     mode;
    4762             :     AclResult   aclresult;
    4763             : 
    4764       92404 :     roleid = GetUserId();
    4765       92404 :     mode = convert_role_priv_string(priv_type_text);
    4766             : 
    4767       92404 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4768             : 
    4769       92404 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4770             : }
    4771             : 
    4772             : /*
    4773             :  * pg_has_role_id_name
    4774             :  *      Check user privileges on a role given
    4775             :  *      roleid, name rolename, and text priv name.
    4776             :  */
    4777             : Datum
    4778           0 : pg_has_role_id_name(PG_FUNCTION_ARGS)
    4779             : {
    4780           0 :     Oid         roleid = PG_GETARG_OID(0);
    4781           0 :     Name        rolename = PG_GETARG_NAME(1);
    4782           0 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4783             :     Oid         roleoid;
    4784             :     AclMode     mode;
    4785             :     AclResult   aclresult;
    4786             : 
    4787           0 :     roleoid = get_role_oid(NameStr(*rolename), false);
    4788           0 :     mode = convert_role_priv_string(priv_type_text);
    4789             : 
    4790           0 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4791             : 
    4792           0 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4793             : }
    4794             : 
    4795             : /*
    4796             :  * pg_has_role_id_id
    4797             :  *      Check user privileges on a role given
    4798             :  *      roleid, role oid, and text priv name.
    4799             :  */
    4800             : Datum
    4801          84 : pg_has_role_id_id(PG_FUNCTION_ARGS)
    4802             : {
    4803          84 :     Oid         roleid = PG_GETARG_OID(0);
    4804          84 :     Oid         roleoid = PG_GETARG_OID(1);
    4805          84 :     text       *priv_type_text = PG_GETARG_TEXT_PP(2);
    4806             :     AclMode     mode;
    4807             :     AclResult   aclresult;
    4808             : 
    4809          84 :     mode = convert_role_priv_string(priv_type_text);
    4810             : 
    4811          84 :     aclresult = pg_role_aclcheck(roleoid, roleid, mode);
    4812             : 
    4813          84 :     PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
    4814             : }
    4815             : 
    4816             : /*
    4817             :  *      Support routines for pg_has_role family.
    4818             :  */
    4819             : 
    4820             : /*
    4821             :  * convert_role_priv_string
    4822             :  *      Convert text string to AclMode value.
    4823             :  *
    4824             :  * We use USAGE to denote whether the privileges of the role are accessible
    4825             :  * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
    4826             :  * (or ADMIN) OPTION to denote is_admin.  There is no ACL bit corresponding
    4827             :  * to MEMBER so we cheat and use ACL_CREATE for that.  This convention
    4828             :  * is shared only with pg_role_aclcheck, below.
    4829             :  */
    4830             : static AclMode
    4831       92542 : convert_role_priv_string(text *priv_type_text)
    4832             : {
    4833             :     static const priv_map role_priv_map[] = {
    4834             :         {"USAGE", ACL_USAGE},
    4835             :         {"MEMBER", ACL_CREATE},
    4836             :         {"SET", ACL_SET},
    4837             :         {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4838             :         {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4839             :         {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4840             :         {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4841             :         {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4842             :         {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
    4843             :         {NULL, 0}
    4844             :     };
    4845             : 
    4846       92542 :     return convert_any_priv_string(priv_type_text, role_priv_map);
    4847             : }
    4848             : 
    4849             : /*
    4850             :  * pg_role_aclcheck
    4851             :  *      Quick-and-dirty support for pg_has_role
    4852             :  */
    4853             : static AclResult
    4854       92542 : pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
    4855             : {
    4856       92542 :     if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
    4857             :     {
    4858          12 :         if (is_admin_of_role(roleid, role_oid))
    4859           0 :             return ACLCHECK_OK;
    4860             :     }
    4861       92542 :     if (mode & ACL_CREATE)
    4862             :     {
    4863          12 :         if (is_member_of_role(roleid, role_oid))
    4864           6 :             return ACLCHECK_OK;
    4865             :     }
    4866       92536 :     if (mode & ACL_USAGE)
    4867             :     {
    4868       92518 :         if (has_privs_of_role(roleid, role_oid))
    4869       91582 :             return ACLCHECK_OK;
    4870             :     }
    4871         954 :     if (mode & ACL_SET)
    4872             :     {
    4873           0 :         if (member_can_set_role(roleid, role_oid))
    4874           0 :             return ACLCHECK_OK;
    4875             :     }
    4876         954 :     return ACLCHECK_NO_PRIV;
    4877             : }
    4878             : 
    4879             : 
    4880             : /*
    4881             :  * initialization function (called by InitPostgres)
    4882             :  */
    4883             : void
    4884       23412 : initialize_acl(void)
    4885             : {
    4886       23412 :     if (!IsBootstrapProcessingMode())
    4887             :     {
    4888       23332 :         cached_db_hash =
    4889       23332 :             GetSysCacheHashValue1(DATABASEOID,
    4890             :                                   ObjectIdGetDatum(MyDatabaseId));
    4891             : 
    4892             :         /*
    4893             :          * In normal mode, set a callback on any syscache invalidation of rows
    4894             :          * of pg_auth_members (for roles_is_member_of()) pg_database (for
    4895             :          * roles_is_member_of())
    4896             :          */
    4897       23332 :         CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
    4898             :                                       RoleMembershipCacheCallback,
    4899             :                                       (Datum) 0);
    4900       23332 :         CacheRegisterSyscacheCallback(AUTHOID,
    4901             :                                       RoleMembershipCacheCallback,
    4902             :                                       (Datum) 0);
    4903       23332 :         CacheRegisterSyscacheCallback(DATABASEOID,
    4904             :                                       RoleMembershipCacheCallback,
    4905             :                                       (Datum) 0);
    4906             :     }
    4907       23412 : }
    4908             : 
    4909             : /*
    4910             :  * RoleMembershipCacheCallback
    4911             :  *      Syscache inval callback function
    4912             :  */
    4913             : static void
    4914       37846 : RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
    4915             : {
    4916       37846 :     if (cacheid == DATABASEOID &&
    4917        6518 :         hashvalue != cached_db_hash &&
    4918             :         hashvalue != 0)
    4919             :     {
    4920        1614 :         return;                 /* ignore pg_database changes for other DBs */
    4921             :     }
    4922             : 
    4923             :     /* Force membership caches to be recomputed on next use */
    4924       36232 :     cached_role[ROLERECURSE_MEMBERS] = InvalidOid;
    4925       36232 :     cached_role[ROLERECURSE_PRIVS] = InvalidOid;
    4926       36232 :     cached_role[ROLERECURSE_SETROLE] = InvalidOid;
    4927             : }
    4928             : 
    4929             : /*
    4930             :  * A helper function for roles_is_member_of() that provides an optimized
    4931             :  * implementation of list_append_unique_oid() via a Bloom filter.  The caller
    4932             :  * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
    4933             :  * using this function.
    4934             :  */
    4935             : static inline List *
    4936        4208 : roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
    4937             : {
    4938        4208 :     unsigned char *roleptr = (unsigned char *) &role;
    4939             : 
    4940             :     /*
    4941             :      * If there is a previously-created Bloom filter, use it to try to
    4942             :      * determine whether the role is missing from the list.  If it says yes,
    4943             :      * that's a hard fact and we can go ahead and add the role.  If it says
    4944             :      * no, that's only probabilistic and we'd better search the list.  Without
    4945             :      * a filter, we must always do an ordinary linear search through the
    4946             :      * existing list.
    4947             :      */
    4948        4208 :     if ((*bf && bloom_lacks_element(*bf, roleptr, sizeof(Oid))) ||
    4949        4208 :         !list_member_oid(roles_list, role))
    4950             :     {
    4951             :         /*
    4952             :          * If the list is large, we take on the overhead of creating and
    4953             :          * populating a Bloom filter to speed up future calls to this
    4954             :          * function.
    4955             :          */
    4956        6736 :         if (*bf == NULL &&
    4957        3368 :             list_length(roles_list) > ROLES_LIST_BLOOM_THRESHOLD)
    4958             :         {
    4959           0 :             *bf = bloom_create(ROLES_LIST_BLOOM_THRESHOLD * 10, work_mem, 0);
    4960           0 :             foreach_oid(roleid, roles_list)
    4961           0 :                 bloom_add_element(*bf, (unsigned char *) &roleid, sizeof(Oid));
    4962             :         }
    4963             : 
    4964             :         /*
    4965             :          * Finally, add the role to the list and the Bloom filter, if it
    4966             :          * exists.
    4967             :          */
    4968        3368 :         roles_list = lappend_oid(roles_list, role);
    4969        3368 :         if (*bf)
    4970           0 :             bloom_add_element(*bf, roleptr, sizeof(Oid));
    4971             :     }
    4972             : 
    4973        4208 :     return roles_list;
    4974             : }
    4975             : 
    4976             : /*
    4977             :  * Get a list of roles that the specified roleid is a member of
    4978             :  *
    4979             :  * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
    4980             :  * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
    4981             :  * only through grants with set_option.
    4982             :  *
    4983             :  * Since indirect membership testing is relatively expensive, we cache
    4984             :  * a list of memberships.  Hence, the result is only guaranteed good until
    4985             :  * the next call of roles_is_member_of()!
    4986             :  *
    4987             :  * For the benefit of select_best_grantor, the result is defined to be
    4988             :  * in breadth-first order, ie, closer relationships earlier.
    4989             :  *
    4990             :  * If admin_of is not InvalidOid, this function sets *admin_role, either
    4991             :  * to the OID of the first role in the result list that directly possesses
    4992             :  * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
    4993             :  * there is no such role.
    4994             :  */
    4995             : static List *
    4996       33912 : roles_is_member_of(Oid roleid, enum RoleRecurseType type,
    4997             :                    Oid admin_of, Oid *admin_role)
    4998             : {
    4999             :     Oid         dba;
    5000             :     List       *roles_list;
    5001             :     ListCell   *l;
    5002             :     List       *new_cached_roles;
    5003             :     MemoryContext oldctx;
    5004       33912 :     bloom_filter *bf = NULL;
    5005             : 
    5006             :     Assert(OidIsValid(admin_of) == PointerIsValid(admin_role));
    5007       33912 :     if (admin_role != NULL)
    5008         866 :         *admin_role = InvalidOid;
    5009             : 
    5010             :     /* If cache is valid and ADMIN OPTION not sought, just return the list */
    5011       33912 :     if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
    5012       29932 :         OidIsValid(cached_role[type]))
    5013       29932 :         return cached_roles[type];
    5014             : 
    5015             :     /*
    5016             :      * Role expansion happens in a non-database backend when guc.c checks
    5017             :      * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command.  In
    5018             :      * that case, no role gets pg_database_owner.
    5019             :      */
    5020        3980 :     if (!OidIsValid(MyDatabaseId))
    5021          30 :         dba = InvalidOid;
    5022             :     else
    5023             :     {
    5024             :         HeapTuple   dbtup;
    5025             : 
    5026        3950 :         dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
    5027        3950 :         if (!HeapTupleIsValid(dbtup))
    5028           0 :             elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
    5029        3950 :         dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
    5030        3950 :         ReleaseSysCache(dbtup);
    5031             :     }
    5032             : 
    5033             :     /*
    5034             :      * Find all the roles that roleid is a member of, including multi-level
    5035             :      * recursion.  The role itself will always be the first element of the
    5036             :      * resulting list.
    5037             :      *
    5038             :      * Each element of the list is scanned to see if it adds any indirect
    5039             :      * memberships.  We can use a single list as both the record of
    5040             :      * already-found memberships and the agenda of roles yet to be scanned.
    5041             :      * This is a bit tricky but works because the foreach() macro doesn't
    5042             :      * fetch the next list element until the bottom of the loop.
    5043             :      */
    5044        3980 :     roles_list = list_make1_oid(roleid);
    5045             : 
    5046       11328 :     foreach(l, roles_list)
    5047             :     {
    5048        7348 :         Oid         memberid = lfirst_oid(l);
    5049             :         CatCList   *memlist;
    5050             :         int         i;
    5051             : 
    5052             :         /* Find roles that memberid is directly a member of */
    5053        7348 :         memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
    5054             :                                       ObjectIdGetDatum(memberid));
    5055       13730 :         for (i = 0; i < memlist->n_members; i++)
    5056             :         {
    5057        6382 :             HeapTuple   tup = &memlist->members[i]->tuple;
    5058        6382 :             Form_pg_auth_members form = (Form_pg_auth_members) GETSTRUCT(tup);
    5059        6382 :             Oid         otherid = form->roleid;
    5060             : 
    5061             :             /*
    5062             :              * While otherid==InvalidOid shouldn't appear in the catalog, the
    5063             :              * OidIsValid() avoids crashing if that arises.
    5064             :              */
    5065        6382 :             if (otherid == admin_of && form->admin_option &&
    5066         728 :                 OidIsValid(admin_of) && !OidIsValid(*admin_role))
    5067         704 :                 *admin_role = memberid;
    5068             : 
    5069             :             /* If we're supposed to ignore non-heritable grants, do so. */
    5070        6382 :             if (type == ROLERECURSE_PRIVS && !form->inherit_option)
    5071        2078 :                 continue;
    5072             : 
    5073             :             /* If we're supposed to ignore non-SET grants, do so. */
    5074        4304 :             if (type == ROLERECURSE_SETROLE && !form->set_option)
    5075         114 :                 continue;
    5076             : 
    5077             :             /*
    5078             :              * Even though there shouldn't be any loops in the membership
    5079             :              * graph, we must test for having already seen this role. It is
    5080             :              * legal for instance to have both A->B and A->C->B.
    5081             :              */
    5082        4190 :             roles_list = roles_list_append(roles_list, &bf, otherid);
    5083             :         }
    5084        7348 :         ReleaseSysCacheList(memlist);
    5085             : 
    5086             :         /* implement pg_database_owner implicit membership */
    5087        7348 :         if (memberid == dba && OidIsValid(dba))
    5088          18 :             roles_list = roles_list_append(roles_list, &bf,
    5089             :                                            ROLE_PG_DATABASE_OWNER);
    5090             :     }
    5091             : 
    5092             :     /*
    5093             :      * Free the Bloom filter created by roles_list_append(), if there is one.
    5094             :      */
    5095        3980 :     if (bf)
    5096           0 :         bloom_free(bf);
    5097             : 
    5098             :     /*
    5099             :      * Copy the completed list into TopMemoryContext so it will persist.
    5100             :      */
    5101        3980 :     oldctx = MemoryContextSwitchTo(TopMemoryContext);
    5102        3980 :     new_cached_roles = list_copy(roles_list);
    5103        3980 :     MemoryContextSwitchTo(oldctx);
    5104        3980 :     list_free(roles_list);
    5105             : 
    5106             :     /*
    5107             :      * Now safe to assign to state variable
    5108             :      */
    5109        3980 :     cached_role[type] = InvalidOid; /* just paranoia */
    5110        3980 :     list_free(cached_roles[type]);
    5111        3980 :     cached_roles[type] = new_cached_roles;
    5112        3980 :     cached_role[type] = roleid;
    5113             : 
    5114             :     /* And now we can return the answer */
    5115        3980 :     return cached_roles[type];
    5116             : }
    5117             : 
    5118             : 
    5119             : /*
    5120             :  * Does member have the privileges of role (directly or indirectly)?
    5121             :  *
    5122             :  * This is defined not to recurse through grants that are not inherited,
    5123             :  * and only inherited grants confer the associated privileges automatically.
    5124             :  *
    5125             :  * See also member_can_set_role, below.
    5126             :  */
    5127             : bool
    5128      334584 : has_privs_of_role(Oid member, Oid role)
    5129             : {
    5130             :     /* Fast path for simple case */
    5131      334584 :     if (member == role)
    5132       95668 :         return true;
    5133             : 
    5134             :     /* Superusers have every privilege, so are part of every role */
    5135      238916 :     if (superuser_arg(member))
    5136      207398 :         return true;
    5137             : 
    5138             :     /*
    5139             :      * Find all the roles that member has the privileges of, including
    5140             :      * multi-level recursion, then see if target role is any one of them.
    5141             :      */
    5142       31518 :     return list_member_oid(roles_is_member_of(member, ROLERECURSE_PRIVS,
    5143             :                                               InvalidOid, NULL),
    5144             :                            role);
    5145             : }
    5146             : 
    5147             : /*
    5148             :  * Can member use SET ROLE to this role?
    5149             :  *
    5150             :  * There must be a chain of grants from 'member' to 'role' each of which
    5151             :  * permits SET ROLE; that is, each of which has set_option = true.
    5152             :  *
    5153             :  * It doesn't matter whether the grants are inheritable. That's a separate
    5154             :  * question; see has_privs_of_role.
    5155             :  *
    5156             :  * This function should be used to determine whether the session user can
    5157             :  * use SET ROLE to become the target user. We also use it to determine whether
    5158             :  * the session user can change an existing object to be owned by the target
    5159             :  * user, or create new objects owned by the target user.
    5160             :  */
    5161             : bool
    5162      595828 : member_can_set_role(Oid member, Oid role)
    5163             : {
    5164             :     /* Fast path for simple case */
    5165      595828 :     if (member == role)
    5166      594510 :         return true;
    5167             : 
    5168             :     /* Superusers have every privilege, so can always SET ROLE */
    5169        1318 :     if (superuser_arg(member))
    5170         918 :         return true;
    5171             : 
    5172             :     /*
    5173             :      * Find all the roles that member can access via SET ROLE, including
    5174             :      * multi-level recursion, then see if target role is any one of them.
    5175             :      */
    5176         400 :     return list_member_oid(roles_is_member_of(member, ROLERECURSE_SETROLE,
    5177             :                                               InvalidOid, NULL),
    5178             :                            role);
    5179             : }
    5180             : 
    5181             : /*
    5182             :  * Permission violation error unless able to SET ROLE to target role.
    5183             :  */
    5184             : void
    5185        1916 : check_can_set_role(Oid member, Oid role)
    5186             : {
    5187        1916 :     if (!member_can_set_role(member, role))
    5188         144 :         ereport(ERROR,
    5189             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    5190             :                  errmsg("must be able to SET ROLE \"%s\"",
    5191             :                         GetUserNameFromId(role, false))));
    5192        1772 : }
    5193             : 
    5194             : /*
    5195             :  * Is member a member of role (directly or indirectly)?
    5196             :  *
    5197             :  * This is defined to recurse through grants whether they are inherited or not.
    5198             :  *
    5199             :  * Do not use this for privilege checking, instead use has_privs_of_role().
    5200             :  * Don't use it for determining whether it's possible to SET ROLE to some
    5201             :  * other role; for that, use member_can_set_role(). And don't use it for
    5202             :  * determining whether it's OK to create an object owned by some other role:
    5203             :  * use member_can_set_role() for that, too.
    5204             :  *
    5205             :  * In short, calling this function is the wrong thing to do nearly everywhere.
    5206             :  */
    5207             : bool
    5208          12 : is_member_of_role(Oid member, Oid role)
    5209             : {
    5210             :     /* Fast path for simple case */
    5211          12 :     if (member == role)
    5212           0 :         return true;
    5213             : 
    5214             :     /* Superusers have every privilege, so are part of every role */
    5215          12 :     if (superuser_arg(member))
    5216           0 :         return true;
    5217             : 
    5218             :     /*
    5219             :      * Find all the roles that member is a member of, including multi-level
    5220             :      * recursion, then see if target role is any one of them.
    5221             :      */
    5222          12 :     return list_member_oid(roles_is_member_of(member, ROLERECURSE_MEMBERS,
    5223             :                                               InvalidOid, NULL),
    5224             :                            role);
    5225             : }
    5226             : 
    5227             : /*
    5228             :  * Is member a member of role, not considering superuserness?
    5229             :  *
    5230             :  * This is identical to is_member_of_role except we ignore superuser
    5231             :  * status.
    5232             :  *
    5233             :  * Do not use this for privilege checking, instead use has_privs_of_role()
    5234             :  */
    5235             : bool
    5236         916 : is_member_of_role_nosuper(Oid member, Oid role)
    5237             : {
    5238             :     /* Fast path for simple case */
    5239         916 :     if (member == role)
    5240          22 :         return true;
    5241             : 
    5242             :     /*
    5243             :      * Find all the roles that member is a member of, including multi-level
    5244             :      * recursion, then see if target role is any one of them.
    5245             :      */
    5246         894 :     return list_member_oid(roles_is_member_of(member, ROLERECURSE_MEMBERS,
    5247             :                                               InvalidOid, NULL),
    5248             :                            role);
    5249             : }
    5250             : 
    5251             : 
    5252             : /*
    5253             :  * Is member an admin of role?  That is, is member the role itself (subject to
    5254             :  * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
    5255             :  * or a superuser?
    5256             :  */
    5257             : bool
    5258        2816 : is_admin_of_role(Oid member, Oid role)
    5259             : {
    5260             :     Oid         admin_role;
    5261             : 
    5262        2816 :     if (superuser_arg(member))
    5263        2352 :         return true;
    5264             : 
    5265             :     /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
    5266         464 :     if (member == role)
    5267          18 :         return false;
    5268             : 
    5269         446 :     (void) roles_is_member_of(member, ROLERECURSE_MEMBERS, role, &admin_role);
    5270         446 :     return OidIsValid(admin_role);
    5271             : }
    5272             : 
    5273             : /*
    5274             :  * Find a role whose privileges "member" inherits which has ADMIN OPTION
    5275             :  * on "role", ignoring super-userness.
    5276             :  *
    5277             :  * There might be more than one such role; prefer one which involves fewer
    5278             :  * hops. That is, if member has ADMIN OPTION, prefer that over all other
    5279             :  * options; if not, prefer a role from which member inherits more directly
    5280             :  * over more indirect inheritance.
    5281             :  */
    5282             : Oid
    5283         426 : select_best_admin(Oid member, Oid role)
    5284             : {
    5285             :     Oid         admin_role;
    5286             : 
    5287             :     /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
    5288         426 :     if (member == role)
    5289           6 :         return InvalidOid;
    5290             : 
    5291         420 :     (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
    5292         420 :     return admin_role;
    5293             : }
    5294             : 
    5295             : 
    5296             : /* does what it says ... */
    5297             : static int
    5298           0 : count_one_bits(AclMode mask)
    5299             : {
    5300           0 :     int         nbits = 0;
    5301             : 
    5302             :     /* this code relies on AclMode being an unsigned type */
    5303           0 :     while (mask)
    5304             :     {
    5305           0 :         if (mask & 1)
    5306           0 :             nbits++;
    5307           0 :         mask >>= 1;
    5308             :     }
    5309           0 :     return nbits;
    5310             : }
    5311             : 
    5312             : 
    5313             : /*
    5314             :  * Select the effective grantor ID for a GRANT or REVOKE operation.
    5315             :  *
    5316             :  * The grantor must always be either the object owner or some role that has
    5317             :  * been explicitly granted grant options.  This ensures that all granted
    5318             :  * privileges appear to flow from the object owner, and there are never
    5319             :  * multiple "original sources" of a privilege.  Therefore, if the would-be
    5320             :  * grantor is a member of a role that has the needed grant options, we have
    5321             :  * to do the grant as that role instead.
    5322             :  *
    5323             :  * It is possible that the would-be grantor is a member of several roles
    5324             :  * that have different subsets of the desired grant options, but no one
    5325             :  * role has 'em all.  In this case we pick a role with the largest number
    5326             :  * of desired options.  Ties are broken in favor of closer ancestors.
    5327             :  *
    5328             :  * roleId: the role attempting to do the GRANT/REVOKE
    5329             :  * privileges: the privileges to be granted/revoked
    5330             :  * acl: the ACL of the object in question
    5331             :  * ownerId: the role owning the object in question
    5332             :  * *grantorId: receives the OID of the role to do the grant as
    5333             :  * *grantOptions: receives the grant options actually held by grantorId
    5334             :  *
    5335             :  * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
    5336             :  */
    5337             : void
    5338       33140 : select_best_grantor(Oid roleId, AclMode privileges,
    5339             :                     const Acl *acl, Oid ownerId,
    5340             :                     Oid *grantorId, AclMode *grantOptions)
    5341             : {
    5342       33140 :     AclMode     needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
    5343             :     List       *roles_list;
    5344             :     int         nrights;
    5345             :     ListCell   *l;
    5346             : 
    5347             :     /*
    5348             :      * The object owner is always treated as having all grant options, so if
    5349             :      * roleId is the owner it's easy.  Also, if roleId is a superuser it's
    5350             :      * easy: superusers are implicitly members of every role, so they act as
    5351             :      * the object owner.
    5352             :      */
    5353       33140 :     if (roleId == ownerId || superuser_arg(roleId))
    5354             :     {
    5355       32918 :         *grantorId = ownerId;
    5356       32918 :         *grantOptions = needed_goptions;
    5357       32918 :         return;
    5358             :     }
    5359             : 
    5360             :     /*
    5361             :      * Otherwise we have to do a careful search to see if roleId has the
    5362             :      * privileges of any suitable role.  Note: we can hang onto the result of
    5363             :      * roles_is_member_of() throughout this loop, because aclmask_direct()
    5364             :      * doesn't query any role memberships.
    5365             :      */
    5366         222 :     roles_list = roles_is_member_of(roleId, ROLERECURSE_PRIVS,
    5367             :                                     InvalidOid, NULL);
    5368             : 
    5369             :     /* initialize candidate result as default */
    5370         222 :     *grantorId = roleId;
    5371         222 :     *grantOptions = ACL_NO_RIGHTS;
    5372         222 :     nrights = 0;
    5373             : 
    5374         300 :     foreach(l, roles_list)
    5375             :     {
    5376         234 :         Oid         otherrole = lfirst_oid(l);
    5377             :         AclMode     otherprivs;
    5378             : 
    5379         234 :         otherprivs = aclmask_direct(acl, otherrole, ownerId,
    5380             :                                     needed_goptions, ACLMASK_ALL);
    5381         234 :         if (otherprivs == needed_goptions)
    5382             :         {
    5383             :             /* Found a suitable grantor */
    5384         156 :             *grantorId = otherrole;
    5385         156 :             *grantOptions = otherprivs;
    5386         156 :             return;
    5387             :         }
    5388             : 
    5389             :         /*
    5390             :          * If it has just some of the needed privileges, remember best
    5391             :          * candidate.
    5392             :          */
    5393          78 :         if (otherprivs != ACL_NO_RIGHTS)
    5394             :         {
    5395           0 :             int         nnewrights = count_one_bits(otherprivs);
    5396             : 
    5397           0 :             if (nnewrights > nrights)
    5398             :             {
    5399           0 :                 *grantorId = otherrole;
    5400           0 :                 *grantOptions = otherprivs;
    5401           0 :                 nrights = nnewrights;
    5402             :             }
    5403             :         }
    5404             :     }
    5405             : }
    5406             : 
    5407             : /*
    5408             :  * get_role_oid - Given a role name, look up the role's OID.
    5409             :  *
    5410             :  * If missing_ok is false, throw an error if role name not found.  If
    5411             :  * true, just return InvalidOid.
    5412             :  */
    5413             : Oid
    5414       33130 : get_role_oid(const char *rolname, bool missing_ok)
    5415             : {
    5416             :     Oid         oid;
    5417             : 
    5418       33130 :     oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
    5419             :                           CStringGetDatum(rolname));
    5420       33130 :     if (!OidIsValid(oid) && !missing_ok)
    5421          64 :         ereport(ERROR,
    5422             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    5423             :                  errmsg("role \"%s\" does not exist", rolname)));
    5424       33066 :     return oid;
    5425             : }
    5426             : 
    5427             : /*
    5428             :  * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
    5429             :  *      role name is "public".
    5430             :  */
    5431             : Oid
    5432         574 : get_role_oid_or_public(const char *rolname)
    5433             : {
    5434         574 :     if (strcmp(rolname, "public") == 0)
    5435           0 :         return ACL_ID_PUBLIC;
    5436             : 
    5437         574 :     return get_role_oid(rolname, false);
    5438             : }
    5439             : 
    5440             : /*
    5441             :  * Given a RoleSpec node, return the OID it corresponds to.  If missing_ok is
    5442             :  * true, return InvalidOid if the role does not exist.
    5443             :  *
    5444             :  * PUBLIC is always disallowed here.  Routines wanting to handle the PUBLIC
    5445             :  * case must check the case separately.
    5446             :  */
    5447             : Oid
    5448        9144 : get_rolespec_oid(const RoleSpec *role, bool missing_ok)
    5449             : {
    5450             :     Oid         oid;
    5451             : 
    5452        9144 :     switch (role->roletype)
    5453             :     {
    5454        8736 :         case ROLESPEC_CSTRING:
    5455             :             Assert(role->rolename);
    5456        8736 :             oid = get_role_oid(role->rolename, missing_ok);
    5457        8686 :             break;
    5458             : 
    5459         370 :         case ROLESPEC_CURRENT_ROLE:
    5460             :         case ROLESPEC_CURRENT_USER:
    5461         370 :             oid = GetUserId();
    5462         370 :             break;
    5463             : 
    5464          22 :         case ROLESPEC_SESSION_USER:
    5465          22 :             oid = GetSessionUserId();
    5466          22 :             break;
    5467             : 
    5468          16 :         case ROLESPEC_PUBLIC:
    5469          16 :             ereport(ERROR,
    5470             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    5471             :                      errmsg("role \"%s\" does not exist", "public")));
    5472             :             oid = InvalidOid;   /* make compiler happy */
    5473             :             break;
    5474             : 
    5475           0 :         default:
    5476           0 :             elog(ERROR, "unexpected role type %d", role->roletype);
    5477             :     }
    5478             : 
    5479        9078 :     return oid;
    5480             : }
    5481             : 
    5482             : /*
    5483             :  * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
    5484             :  * Caller must ReleaseSysCache when done with the result tuple.
    5485             :  */
    5486             : HeapTuple
    5487         634 : get_rolespec_tuple(const RoleSpec *role)
    5488             : {
    5489             :     HeapTuple   tuple;
    5490             : 
    5491         634 :     switch (role->roletype)
    5492             :     {
    5493         582 :         case ROLESPEC_CSTRING:
    5494             :             Assert(role->rolename);
    5495         582 :             tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
    5496         582 :             if (!HeapTupleIsValid(tuple))
    5497          12 :                 ereport(ERROR,
    5498             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    5499             :                          errmsg("role \"%s\" does not exist", role->rolename)));
    5500         570 :             break;
    5501             : 
    5502          28 :         case ROLESPEC_CURRENT_ROLE:
    5503             :         case ROLESPEC_CURRENT_USER:
    5504          28 :             tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
    5505          28 :             if (!HeapTupleIsValid(tuple))
    5506           0 :                 elog(ERROR, "cache lookup failed for role %u", GetUserId());
    5507          28 :             break;
    5508             : 
    5509          12 :         case ROLESPEC_SESSION_USER:
    5510          12 :             tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetSessionUserId()));
    5511          12 :             if (!HeapTupleIsValid(tuple))
    5512           0 :                 elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
    5513          12 :             break;
    5514             : 
    5515          12 :         case ROLESPEC_PUBLIC:
    5516          12 :             ereport(ERROR,
    5517             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    5518             :                      errmsg("role \"%s\" does not exist", "public")));
    5519             :             tuple = NULL;       /* make compiler happy */
    5520             :             break;
    5521             : 
    5522           0 :         default:
    5523           0 :             elog(ERROR, "unexpected role type %d", role->roletype);
    5524             :     }
    5525             : 
    5526         610 :     return tuple;
    5527             : }
    5528             : 
    5529             : /*
    5530             :  * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
    5531             :  */
    5532             : char *
    5533          42 : get_rolespec_name(const RoleSpec *role)
    5534             : {
    5535             :     HeapTuple   tp;
    5536             :     Form_pg_authid authForm;
    5537             :     char       *rolename;
    5538             : 
    5539          42 :     tp = get_rolespec_tuple(role);
    5540          42 :     authForm = (Form_pg_authid) GETSTRUCT(tp);
    5541          42 :     rolename = pstrdup(NameStr(authForm->rolname));
    5542          42 :     ReleaseSysCache(tp);
    5543             : 
    5544          42 :     return rolename;
    5545             : }
    5546             : 
    5547             : /*
    5548             :  * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
    5549             :  * if provided (which must be already translated).
    5550             :  *
    5551             :  * If node is NULL, no error is thrown.  If detail_msg is NULL then no detail
    5552             :  * message is provided.
    5553             :  */
    5554             : void
    5555         492 : check_rolespec_name(const RoleSpec *role, const char *detail_msg)
    5556             : {
    5557         492 :     if (!role)
    5558           0 :         return;
    5559             : 
    5560         492 :     if (role->roletype != ROLESPEC_CSTRING)
    5561          52 :         return;
    5562             : 
    5563         440 :     if (IsReservedName(role->rolename))
    5564             :     {
    5565           0 :         if (detail_msg)
    5566           0 :             ereport(ERROR,
    5567             :                     (errcode(ERRCODE_RESERVED_NAME),
    5568             :                      errmsg("role name \"%s\" is reserved",
    5569             :                             role->rolename),
    5570             :                      errdetail_internal("%s", detail_msg)));
    5571             :         else
    5572           0 :             ereport(ERROR,
    5573             :                     (errcode(ERRCODE_RESERVED_NAME),
    5574             :                      errmsg("role name \"%s\" is reserved",
    5575             :                             role->rolename)));
    5576             :     }
    5577             : }

Generated by: LCOV version 1.14