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

Generated by: LCOV version 2.0-1