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

Generated by: LCOV version 1.14