LCOV - code coverage report
Current view: top level - src/backend/parser - parse_oper.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 93.1 % 290 270
Test Date: 2026-07-08 09:15:42 Functions: 95.0 % 20 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 69.7 % 218 152

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * parse_oper.c
       4                 :             :  *      handle operator things for parser
       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/parser/parse_oper.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "access/htup_details.h"
      19                 :             : #include "catalog/pg_operator.h"
      20                 :             : #include "catalog/pg_type.h"
      21                 :             : #include "lib/stringinfo.h"
      22                 :             : #include "nodes/nodeFuncs.h"
      23                 :             : #include "parser/parse_coerce.h"
      24                 :             : #include "parser/parse_func.h"
      25                 :             : #include "parser/parse_oper.h"
      26                 :             : #include "parser/parse_type.h"
      27                 :             : #include "utils/builtins.h"
      28                 :             : #include "utils/hsearch.h"
      29                 :             : #include "utils/inval.h"
      30                 :             : #include "utils/lsyscache.h"
      31                 :             : #include "utils/syscache.h"
      32                 :             : #include "utils/typcache.h"
      33                 :             : 
      34                 :             : 
      35                 :             : /*
      36                 :             :  * The lookup key for the operator lookaside hash table.  Unused bits must be
      37                 :             :  * zeroes to ensure hashing works consistently --- in particular, oprname
      38                 :             :  * must be zero-padded and any unused entries in search_path must be zero.
      39                 :             :  *
      40                 :             :  * search_path contains the actual search_path with which the entry was
      41                 :             :  * derived (minus temp namespace if any), or else the single specified
      42                 :             :  * schema OID if we are looking up an explicitly-qualified operator name.
      43                 :             :  *
      44                 :             :  * search_path has to be fixed-length since the hashtable code insists on
      45                 :             :  * fixed-size keys.  If your search path is longer than that, we just punt
      46                 :             :  * and don't cache anything.
      47                 :             :  */
      48                 :             : 
      49                 :             : /* If your search_path is longer than this, sucks to be you ... */
      50                 :             : #define MAX_CACHED_PATH_LEN     16
      51                 :             : 
      52                 :             : typedef struct OprCacheKey
      53                 :             : {
      54                 :             :     char        oprname[NAMEDATALEN];
      55                 :             :     Oid         left_arg;       /* Left input OID, or 0 if prefix op */
      56                 :             :     Oid         right_arg;      /* Right input OID */
      57                 :             :     Oid         search_path[MAX_CACHED_PATH_LEN];
      58                 :             : } OprCacheKey;
      59                 :             : 
      60                 :             : typedef struct OprCacheEntry
      61                 :             : {
      62                 :             :     /* the hash lookup key MUST BE FIRST */
      63                 :             :     OprCacheKey key;
      64                 :             : 
      65                 :             :     Oid         opr_oid;        /* OID of the resolved operator */
      66                 :             : } OprCacheEntry;
      67                 :             : 
      68                 :             : 
      69                 :             : static Oid  binary_oper_exact(List *opname, Oid arg1, Oid arg2);
      70                 :             : static FuncDetailCode oper_select_candidate(int nargs,
      71                 :             :                                             Oid *input_typeids,
      72                 :             :                                             FuncCandidateList candidates,
      73                 :             :                                             Oid *operOid);
      74                 :             : static void op_error(ParseState *pstate, List *op,
      75                 :             :                      Oid arg1, Oid arg2,
      76                 :             :                      FuncDetailCode fdresult, int fgc_flags, int location);
      77                 :             : static int  oper_lookup_failure_details(int fgc_flags, bool is_unary_op);
      78                 :             : static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
      79                 :             :                                 List *opname, Oid ltypeId, Oid rtypeId,
      80                 :             :                                 int location);
      81                 :             : static Oid  find_oper_cache_entry(OprCacheKey *key);
      82                 :             : static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
      83                 :             : static void InvalidateOprCacheCallBack(Datum arg, SysCacheIdentifier cacheid,
      84                 :             :                                        uint32 hashvalue);
      85                 :             : 
      86                 :             : 
      87                 :             : /*
      88                 :             :  * LookupOperName
      89                 :             :  *      Given a possibly-qualified operator name and exact input datatypes,
      90                 :             :  *      look up the operator.
      91                 :             :  *
      92                 :             :  * Pass oprleft = InvalidOid for a prefix op.
      93                 :             :  *
      94                 :             :  * If the operator name is not schema-qualified, it is sought in the current
      95                 :             :  * namespace search path.
      96                 :             :  *
      97                 :             :  * If the operator is not found, we return InvalidOid if noError is true,
      98                 :             :  * else raise an error.  pstate and location are used only to report the
      99                 :             :  * error position; pass NULL/-1 if not available.
     100                 :             :  */
     101                 :             : Oid
     102                 :        3250 : LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
     103                 :             :                bool noError, int location)
     104                 :             : {
     105                 :             :     Oid         result;
     106                 :             : 
     107                 :        3250 :     result = OpernameGetOprid(opername, oprleft, oprright);
     108         [ +  + ]:        3250 :     if (OidIsValid(result))
     109                 :        2785 :         return result;
     110                 :             : 
     111                 :             :     /* we don't use op_error here because only an exact match is wanted */
     112         [ +  + ]:         465 :     if (!noError)
     113                 :             :     {
     114         [ +  + ]:          32 :         if (!OidIsValid(oprright))
     115         [ +  - ]:           8 :             ereport(ERROR,
     116                 :             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     117                 :             :                      errmsg("postfix operators are not supported"),
     118                 :             :                      parser_errposition(pstate, location)));
     119                 :             : 
     120         [ +  - ]:          24 :         ereport(ERROR,
     121                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     122                 :             :                  errmsg("operator does not exist: %s",
     123                 :             :                         op_signature_string(opername, oprleft, oprright)),
     124                 :             :                  parser_errposition(pstate, location)));
     125                 :             :     }
     126                 :             : 
     127                 :         433 :     return InvalidOid;
     128                 :             : }
     129                 :             : 
     130                 :             : /*
     131                 :             :  * LookupOperWithArgs
     132                 :             :  *      Like LookupOperName, but the argument types are specified by
     133                 :             :  *      a ObjectWithArgs node.
     134                 :             :  */
     135                 :             : Oid
     136                 :        1270 : LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
     137                 :             : {
     138                 :             :     TypeName   *oprleft,
     139                 :             :                *oprright;
     140                 :             :     Oid         leftoid,
     141                 :             :                 rightoid;
     142                 :             : 
     143                 :             :     Assert(list_length(oper->objargs) == 2);
     144                 :        1270 :     oprleft = linitial_node(TypeName, oper->objargs);
     145                 :        1270 :     oprright = lsecond_node(TypeName, oper->objargs);
     146                 :             : 
     147         [ +  + ]:        1270 :     if (oprleft == NULL)
     148                 :          20 :         leftoid = InvalidOid;
     149                 :             :     else
     150                 :        1250 :         leftoid = LookupTypeNameOid(NULL, oprleft, noError);
     151                 :             : 
     152         [ +  + ]:        1266 :     if (oprright == NULL)
     153                 :           8 :         rightoid = InvalidOid;
     154                 :             :     else
     155                 :        1258 :         rightoid = LookupTypeNameOid(NULL, oprright, noError);
     156                 :             : 
     157                 :        1262 :     return LookupOperName(NULL, oper->objname, leftoid, rightoid,
     158                 :             :                           noError, -1);
     159                 :             : }
     160                 :             : 
     161                 :             : /*
     162                 :             :  * get_sort_group_operators - get default sorting/grouping operators for type
     163                 :             :  *
     164                 :             :  * We fetch the "<", "=", and ">" operators all at once to reduce lookup
     165                 :             :  * overhead (knowing that most callers will be interested in at least two).
     166                 :             :  * However, a given datatype might have only an "=" operator, if it is
     167                 :             :  * hashable but not sortable.  (Other combinations of present and missing
     168                 :             :  * operators shouldn't happen, unless the system catalogs are messed up.)
     169                 :             :  *
     170                 :             :  * If an operator is missing and the corresponding needXX flag is true,
     171                 :             :  * throw a standard error message, else return InvalidOid.
     172                 :             :  *
     173                 :             :  * In addition to the operator OIDs themselves, this function can identify
     174                 :             :  * whether the "=" operator is hashable.
     175                 :             :  *
     176                 :             :  * Callers can pass NULL pointers for any results they don't care to get.
     177                 :             :  *
     178                 :             :  * Note: the results are guaranteed to be exact or binary-compatible matches,
     179                 :             :  * since most callers are not prepared to cope with adding any run-time type
     180                 :             :  * coercion steps.
     181                 :             :  */
     182                 :             : void
     183                 :      179428 : get_sort_group_operators(Oid argtype,
     184                 :             :                          bool needLT, bool needEQ, bool needGT,
     185                 :             :                          Oid *ltOpr, Oid *eqOpr, Oid *gtOpr,
     186                 :             :                          bool *isHashable)
     187                 :             : {
     188                 :             :     TypeCacheEntry *typentry;
     189                 :             :     int         cache_flags;
     190                 :             :     Oid         lt_opr;
     191                 :             :     Oid         eq_opr;
     192                 :             :     Oid         gt_opr;
     193                 :             :     bool        hashable;
     194                 :             : 
     195                 :             :     /*
     196                 :             :      * Look up the operators using the type cache.
     197                 :             :      *
     198                 :             :      * Note: the search algorithm used by typcache.c ensures that the results
     199                 :             :      * are consistent, ie all from matching opclasses.
     200                 :             :      */
     201         [ +  + ]:      179428 :     if (isHashable != NULL)
     202                 :      104385 :         cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR |
     203                 :             :             TYPECACHE_HASH_PROC;
     204                 :             :     else
     205                 :       75043 :         cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR;
     206                 :             : 
     207                 :      179428 :     typentry = lookup_type_cache(argtype, cache_flags);
     208                 :      179428 :     lt_opr = typentry->lt_opr;
     209                 :      179428 :     eq_opr = typentry->eq_opr;
     210                 :      179428 :     gt_opr = typentry->gt_opr;
     211                 :      179428 :     hashable = OidIsValid(typentry->hash_proc);
     212                 :             : 
     213                 :             :     /* Report errors if needed */
     214   [ +  +  +  +  :      179428 :     if ((needLT && !OidIsValid(lt_opr)) ||
                   +  + ]
     215         [ -  + ]:        2369 :         (needGT && !OidIsValid(gt_opr)))
     216         [ +  - ]:           4 :         ereport(ERROR,
     217                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     218                 :             :                  errmsg("could not identify an ordering operator for type %s",
     219                 :             :                         format_type_be(argtype)),
     220                 :             :                  errhint("Use an explicit ordering operator or modify the query.")));
     221   [ +  +  -  + ]:      179424 :     if (needEQ && !OidIsValid(eq_opr))
     222         [ #  # ]:           0 :         ereport(ERROR,
     223                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     224                 :             :                  errmsg("could not identify an equality operator for type %s",
     225                 :             :                         format_type_be(argtype))));
     226                 :             : 
     227                 :             :     /* Return results as needed */
     228         [ +  + ]:      179424 :     if (ltOpr)
     229                 :      177055 :         *ltOpr = lt_opr;
     230         [ +  - ]:      179424 :     if (eqOpr)
     231                 :      179424 :         *eqOpr = eq_opr;
     232         [ +  + ]:      179424 :     if (gtOpr)
     233                 :        2369 :         *gtOpr = gt_opr;
     234         [ +  + ]:      179424 :     if (isHashable)
     235                 :      104381 :         *isHashable = hashable;
     236                 :      179424 : }
     237                 :             : 
     238                 :             : 
     239                 :             : /* given operator tuple, return the operator OID */
     240                 :             : Oid
     241                 :      462686 : oprid(Operator op)
     242                 :             : {
     243                 :      462686 :     return ((Form_pg_operator) GETSTRUCT(op))->oid;
     244                 :             : }
     245                 :             : 
     246                 :             : /* given operator tuple, return the underlying function's OID */
     247                 :             : Oid
     248                 :           0 : oprfuncid(Operator op)
     249                 :             : {
     250                 :           0 :     Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
     251                 :             : 
     252                 :           0 :     return pgopform->oprcode;
     253                 :             : }
     254                 :             : 
     255                 :             : 
     256                 :             : /*
     257                 :             :  * binary_oper_exact()
     258                 :             :  * Check for an "exact" match to the specified operand types.
     259                 :             :  *
     260                 :             :  * If one operand is an unknown literal, assume it should be taken to be
     261                 :             :  * the same type as the other operand for this purpose.  Also, consider
     262                 :             :  * the possibility that the other operand is a domain type that needs to
     263                 :             :  * be reduced to its base type to find an "exact" match.
     264                 :             :  */
     265                 :             : static Oid
     266                 :       49656 : binary_oper_exact(List *opname, Oid arg1, Oid arg2)
     267                 :             : {
     268                 :             :     Oid         result;
     269                 :       49656 :     bool        was_unknown = false;
     270                 :             : 
     271                 :             :     /* Unspecified type for one of the arguments? then use the other */
     272   [ +  +  +  - ]:       49656 :     if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
     273                 :             :     {
     274                 :        2258 :         arg1 = arg2;
     275                 :        2258 :         was_unknown = true;
     276                 :             :     }
     277   [ +  +  +  - ]:       47398 :     else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
     278                 :             :     {
     279                 :       12820 :         arg2 = arg1;
     280                 :       12820 :         was_unknown = true;
     281                 :             :     }
     282                 :             : 
     283                 :       49656 :     result = OpernameGetOprid(opname, arg1, arg2);
     284         [ +  + ]:       49656 :     if (OidIsValid(result))
     285                 :       37969 :         return result;
     286                 :             : 
     287         [ +  + ]:       11687 :     if (was_unknown)
     288                 :             :     {
     289                 :             :         /* arg1 and arg2 are the same here, need only look at arg1 */
     290                 :        3118 :         Oid         basetype = getBaseType(arg1);
     291                 :             : 
     292         [ +  + ]:        3118 :         if (basetype != arg1)
     293                 :             :         {
     294                 :         213 :             result = OpernameGetOprid(opname, basetype, basetype);
     295         [ +  + ]:         213 :             if (OidIsValid(result))
     296                 :          47 :                 return result;
     297                 :             :         }
     298                 :             :     }
     299                 :             : 
     300                 :       11640 :     return InvalidOid;
     301                 :             : }
     302                 :             : 
     303                 :             : 
     304                 :             : /*
     305                 :             :  * oper_select_candidate()
     306                 :             :  *      Given the input argtype array and one or more candidates
     307                 :             :  *      for the operator, attempt to resolve the conflict.
     308                 :             :  *
     309                 :             :  * Returns FUNCDETAIL_NOTFOUND, FUNCDETAIL_MULTIPLE, or FUNCDETAIL_NORMAL.
     310                 :             :  * In the success case the Oid of the best candidate is stored in *operOid.
     311                 :             :  *
     312                 :             :  * Note that the caller has already determined that there is no candidate
     313                 :             :  * exactly matching the input argtype(s).  Incompatible candidates are not yet
     314                 :             :  * pruned away, however.
     315                 :             :  */
     316                 :             : static FuncDetailCode
     317                 :       11663 : oper_select_candidate(int nargs,
     318                 :             :                       Oid *input_typeids,
     319                 :             :                       FuncCandidateList candidates,
     320                 :             :                       Oid *operOid) /* output argument */
     321                 :             : {
     322                 :             :     int         ncandidates;
     323                 :             : 
     324                 :             :     /*
     325                 :             :      * Delete any candidates that cannot actually accept the given input
     326                 :             :      * types, whether directly or by coercion.
     327                 :             :      */
     328                 :       11663 :     ncandidates = func_match_argtypes(nargs, input_typeids,
     329                 :             :                                       candidates, &candidates);
     330                 :             : 
     331                 :             :     /* Done if no candidate or only one candidate survives */
     332         [ +  + ]:       11663 :     if (ncandidates == 0)
     333                 :             :     {
     334                 :          79 :         *operOid = InvalidOid;
     335                 :          79 :         return FUNCDETAIL_NOTFOUND;
     336                 :             :     }
     337         [ +  + ]:       11584 :     if (ncandidates == 1)
     338                 :             :     {
     339                 :        7639 :         *operOid = candidates->oid;
     340                 :        7639 :         return FUNCDETAIL_NORMAL;
     341                 :             :     }
     342                 :             : 
     343                 :             :     /*
     344                 :             :      * Use the same heuristics as for ambiguous functions to resolve the
     345                 :             :      * conflict.
     346                 :             :      */
     347                 :        3945 :     candidates = func_select_candidate(nargs, input_typeids, candidates);
     348                 :             : 
     349         [ +  + ]:        3945 :     if (candidates)
     350                 :             :     {
     351                 :        3941 :         *operOid = candidates->oid;
     352                 :        3941 :         return FUNCDETAIL_NORMAL;
     353                 :             :     }
     354                 :             : 
     355                 :           4 :     *operOid = InvalidOid;
     356                 :           4 :     return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */
     357                 :             : }
     358                 :             : 
     359                 :             : 
     360                 :             : /*
     361                 :             :  * oper() -- search for a binary operator
     362                 :             :  * Given operator name, types of arg1 and arg2, return oper struct.
     363                 :             :  *
     364                 :             :  * IMPORTANT: the returned operator (if any) is only promised to be
     365                 :             :  * coercion-compatible with the input datatypes.  Do not use this if
     366                 :             :  * you need an exact- or binary-compatible match; see compatible_oper.
     367                 :             :  *
     368                 :             :  * If no matching operator found, return NULL if noError is true,
     369                 :             :  * raise an error if it is false.  pstate and location are used only to report
     370                 :             :  * the error position; pass NULL/-1 if not available.
     371                 :             :  *
     372                 :             :  * NOTE: on success, the returned object is a syscache entry.  The caller
     373                 :             :  * must ReleaseSysCache() the entry when done with it.
     374                 :             :  */
     375                 :             : Operator
     376                 :      461944 : oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
     377                 :             :      bool noError, int location)
     378                 :             : {
     379                 :             :     Oid         operOid;
     380                 :             :     OprCacheKey key;
     381                 :             :     bool        key_ok;
     382                 :      461944 :     int         fgc_flags = 0;
     383                 :      461944 :     FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
     384                 :      461944 :     HeapTuple   tup = NULL;
     385                 :             : 
     386                 :             :     /*
     387                 :             :      * Try to find the mapping in the lookaside cache.
     388                 :             :      */
     389                 :      461944 :     key_ok = make_oper_cache_key(pstate, &key, opname, ltypeId, rtypeId, location);
     390                 :             : 
     391         [ +  - ]:      461944 :     if (key_ok)
     392                 :             :     {
     393                 :      461944 :         operOid = find_oper_cache_entry(&key);
     394         [ +  + ]:      461944 :         if (OidIsValid(operOid))
     395                 :             :         {
     396                 :      412288 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     397         [ +  - ]:      412288 :             if (HeapTupleIsValid(tup))
     398                 :      412288 :                 return (Operator) tup;
     399                 :             :         }
     400                 :             :     }
     401                 :             : 
     402                 :             :     /*
     403                 :             :      * First try for an "exact" match.
     404                 :             :      */
     405                 :       49656 :     operOid = binary_oper_exact(opname, ltypeId, rtypeId);
     406         [ +  + ]:       49656 :     if (!OidIsValid(operOid))
     407                 :             :     {
     408                 :             :         /*
     409                 :             :          * Otherwise, search for the most suitable candidate.
     410                 :             :          */
     411                 :             :         FuncCandidateList clist;
     412                 :             : 
     413                 :             :         /* Get binary operators of given name */
     414                 :       11640 :         clist = OpernameGetCandidates(opname, 'b', false, &fgc_flags);
     415                 :             : 
     416                 :             :         /* No operators found? Then fail... */
     417         [ +  - ]:       11640 :         if (clist != NULL)
     418                 :             :         {
     419                 :             :             /*
     420                 :             :              * Unspecified type for one of the arguments? then use the other
     421                 :             :              * (XXX this is probably dead code?)
     422                 :             :              */
     423                 :             :             Oid         inputOids[2];
     424                 :             : 
     425         [ -  + ]:       11640 :             if (rtypeId == InvalidOid)
     426                 :           0 :                 rtypeId = ltypeId;
     427         [ -  + ]:       11640 :             else if (ltypeId == InvalidOid)
     428                 :           0 :                 ltypeId = rtypeId;
     429                 :       11640 :             inputOids[0] = ltypeId;
     430                 :       11640 :             inputOids[1] = rtypeId;
     431                 :       11640 :             fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
     432                 :             :         }
     433                 :             :     }
     434                 :             : 
     435         [ +  + ]:       49656 :     if (OidIsValid(operOid))
     436                 :       49577 :         tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     437                 :             : 
     438         [ +  + ]:       49656 :     if (HeapTupleIsValid(tup))
     439                 :             :     {
     440         [ +  - ]:       49577 :         if (key_ok)
     441                 :       49577 :             make_oper_cache_entry(&key, operOid);
     442                 :             :     }
     443         [ +  + ]:          79 :     else if (!noError)
     444                 :          74 :         op_error(pstate, opname, ltypeId, rtypeId,
     445                 :             :                  fdresult, fgc_flags, location);
     446                 :             : 
     447                 :       49582 :     return (Operator) tup;
     448                 :             : }
     449                 :             : 
     450                 :             : /*
     451                 :             :  * compatible_oper()
     452                 :             :  *  given an opname and input datatypes, find a compatible binary operator
     453                 :             :  *
     454                 :             :  *  This is tighter than oper() because it will not return an operator that
     455                 :             :  *  requires coercion of the input datatypes (but binary-compatible operators
     456                 :             :  *  are accepted).  Otherwise, the semantics are the same.
     457                 :             :  */
     458                 :             : Operator
     459                 :         370 : compatible_oper(ParseState *pstate, List *op, Oid arg1, Oid arg2,
     460                 :             :                 bool noError, int location)
     461                 :             : {
     462                 :             :     Operator    optup;
     463                 :             :     Form_pg_operator opform;
     464                 :             : 
     465                 :             :     /* oper() will find the best available match */
     466                 :         370 :     optup = oper(pstate, op, arg1, arg2, noError, location);
     467         [ -  + ]:         370 :     if (optup == (Operator) NULL)
     468                 :           0 :         return (Operator) NULL; /* must be noError case */
     469                 :             : 
     470                 :             :     /* but is it good enough? */
     471                 :         370 :     opform = (Form_pg_operator) GETSTRUCT(optup);
     472   [ +  -  +  - ]:         740 :     if (IsBinaryCoercible(arg1, opform->oprleft) &&
     473                 :         370 :         IsBinaryCoercible(arg2, opform->oprright))
     474                 :         370 :         return optup;
     475                 :             : 
     476                 :             :     /* nope... */
     477                 :           0 :     ReleaseSysCache(optup);
     478                 :             : 
     479         [ #  # ]:           0 :     if (!noError)
     480         [ #  # ]:           0 :         ereport(ERROR,
     481                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     482                 :             :                  errmsg("operator requires run-time type coercion: %s",
     483                 :             :                         op_signature_string(op, arg1, arg2)),
     484                 :             :                  parser_errposition(pstate, location)));
     485                 :             : 
     486                 :           0 :     return (Operator) NULL;
     487                 :             : }
     488                 :             : 
     489                 :             : /*
     490                 :             :  * compatible_oper_opid() -- get OID of a binary operator
     491                 :             :  *
     492                 :             :  * This is a convenience routine that extracts only the operator OID
     493                 :             :  * from the result of compatible_oper().  InvalidOid is returned if the
     494                 :             :  * lookup fails and noError is true.
     495                 :             :  */
     496                 :             : Oid
     497                 :         370 : compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
     498                 :             : {
     499                 :             :     Operator    optup;
     500                 :             :     Oid         result;
     501                 :             : 
     502                 :         370 :     optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
     503         [ +  - ]:         370 :     if (optup != NULL)
     504                 :             :     {
     505                 :         370 :         result = oprid(optup);
     506                 :         370 :         ReleaseSysCache(optup);
     507                 :         370 :         return result;
     508                 :             :     }
     509                 :           0 :     return InvalidOid;
     510                 :             : }
     511                 :             : 
     512                 :             : 
     513                 :             : /*
     514                 :             :  * left_oper() -- search for a unary left operator (prefix operator)
     515                 :             :  * Given operator name and type of arg, return oper struct.
     516                 :             :  *
     517                 :             :  * IMPORTANT: the returned operator (if any) is only promised to be
     518                 :             :  * coercion-compatible with the input datatype.  Do not use this if
     519                 :             :  * you need an exact- or binary-compatible match.
     520                 :             :  *
     521                 :             :  * If no matching operator found, return NULL if noError is true,
     522                 :             :  * raise an error if it is false.  pstate and location are used only to report
     523                 :             :  * the error position; pass NULL/-1 if not available.
     524                 :             :  *
     525                 :             :  * NOTE: on success, the returned object is a syscache entry.  The caller
     526                 :             :  * must ReleaseSysCache() the entry when done with it.
     527                 :             :  */
     528                 :             : Operator
     529                 :         841 : left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
     530                 :             : {
     531                 :             :     Oid         operOid;
     532                 :             :     OprCacheKey key;
     533                 :             :     bool        key_ok;
     534                 :         841 :     int         fgc_flags = 0;
     535                 :         841 :     FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
     536                 :         841 :     HeapTuple   tup = NULL;
     537                 :             : 
     538                 :             :     /*
     539                 :             :      * Try to find the mapping in the lookaside cache.
     540                 :             :      */
     541                 :         841 :     key_ok = make_oper_cache_key(pstate, &key, op, InvalidOid, arg, location);
     542                 :             : 
     543         [ +  - ]:         841 :     if (key_ok)
     544                 :             :     {
     545                 :         841 :         operOid = find_oper_cache_entry(&key);
     546         [ +  + ]:         841 :         if (OidIsValid(operOid))
     547                 :             :         {
     548                 :         525 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     549         [ +  - ]:         525 :             if (HeapTupleIsValid(tup))
     550                 :         525 :                 return (Operator) tup;
     551                 :             :         }
     552                 :             :     }
     553                 :             : 
     554                 :             :     /*
     555                 :             :      * First try for an "exact" match.
     556                 :             :      */
     557                 :         316 :     operOid = OpernameGetOprid(op, InvalidOid, arg);
     558         [ +  + ]:         316 :     if (!OidIsValid(operOid))
     559                 :             :     {
     560                 :             :         /*
     561                 :             :          * Otherwise, search for the most suitable candidate.
     562                 :             :          */
     563                 :             :         FuncCandidateList clist;
     564                 :             : 
     565                 :             :         /* Get prefix operators of given name */
     566                 :          31 :         clist = OpernameGetCandidates(op, 'l', false, &fgc_flags);
     567                 :             : 
     568                 :             :         /* No operators found? Then fail... */
     569         [ +  + ]:          31 :         if (clist != NULL)
     570                 :             :         {
     571                 :             :             /*
     572                 :             :              * The returned list has args in the form (0, oprright). Move the
     573                 :             :              * useful data into args[0] to keep oper_select_candidate simple.
     574                 :             :              * XXX we are assuming here that we may scribble on the list!
     575                 :             :              */
     576                 :             :             FuncCandidateList clisti;
     577                 :             : 
     578         [ +  + ]:          75 :             for (clisti = clist; clisti != NULL; clisti = clisti->next)
     579                 :             :             {
     580                 :          52 :                 clisti->args[0] = clisti->args[1];
     581                 :             :             }
     582                 :             : 
     583                 :             :             /*
     584                 :             :              * We must run oper_select_candidate even if only one candidate,
     585                 :             :              * otherwise we may falsely return a non-type-compatible operator.
     586                 :             :              */
     587                 :          23 :             fdresult = oper_select_candidate(1, &arg, clist, &operOid);
     588                 :             :         }
     589                 :             :     }
     590                 :             : 
     591         [ +  + ]:         316 :     if (OidIsValid(operOid))
     592                 :         304 :         tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     593                 :             : 
     594         [ +  + ]:         316 :     if (HeapTupleIsValid(tup))
     595                 :             :     {
     596         [ +  - ]:         304 :         if (key_ok)
     597                 :         304 :             make_oper_cache_entry(&key, operOid);
     598                 :             :     }
     599         [ +  - ]:          12 :     else if (!noError)
     600                 :          12 :         op_error(pstate, op, InvalidOid, arg,
     601                 :             :                  fdresult, fgc_flags, location);
     602                 :             : 
     603                 :         304 :     return (Operator) tup;
     604                 :             : }
     605                 :             : 
     606                 :             : /*
     607                 :             :  * op_signature_string
     608                 :             :  *      Build a string representing an operator name, including arg type(s).
     609                 :             :  *      The result is something like "integer + integer".
     610                 :             :  *
     611                 :             :  * This is typically used in the construction of operator-not-found error
     612                 :             :  * messages.
     613                 :             :  */
     614                 :             : const char *
     615                 :         110 : op_signature_string(List *op, Oid arg1, Oid arg2)
     616                 :             : {
     617                 :             :     StringInfoData argbuf;
     618                 :             : 
     619                 :         110 :     initStringInfo(&argbuf);
     620                 :             : 
     621         [ +  + ]:         110 :     if (OidIsValid(arg1))
     622                 :          90 :         appendStringInfo(&argbuf, "%s ", format_type_be(arg1));
     623                 :             : 
     624                 :         110 :     appendStringInfoString(&argbuf, NameListToString(op));
     625                 :             : 
     626                 :         110 :     appendStringInfo(&argbuf, " %s", format_type_be(arg2));
     627                 :             : 
     628                 :         110 :     return argbuf.data;         /* return palloc'd string buffer */
     629                 :             : }
     630                 :             : 
     631                 :             : /*
     632                 :             :  * op_error - utility routine to complain about an unresolvable operator
     633                 :             :  */
     634                 :             : static void
     635                 :          86 : op_error(ParseState *pstate, List *op,
     636                 :             :          Oid arg1, Oid arg2,
     637                 :             :          FuncDetailCode fdresult, int fgc_flags, int location)
     638                 :             : {
     639         [ +  + ]:          86 :     if (fdresult == FUNCDETAIL_MULTIPLE)
     640         [ +  - ]:           4 :         ereport(ERROR,
     641                 :             :                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     642                 :             :                  errmsg("operator is not unique: %s",
     643                 :             :                         op_signature_string(op, arg1, arg2)),
     644                 :             :                  errdetail("Could not choose a best candidate operator."),
     645                 :             :                  errhint("You might need to add explicit type casts."),
     646                 :             :                  parser_errposition(pstate, location)));
     647                 :             :     else
     648   [ +  -  +  +  :          82 :         ereport(ERROR,
                   -  + ]
     649                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     650                 :             :                  errmsg("operator does not exist: %s",
     651                 :             :                         op_signature_string(op, arg1, arg2)),
     652                 :             :                  oper_lookup_failure_details(fgc_flags, (!arg1 || !arg2)),
     653                 :             :                  parser_errposition(pstate, location)));
     654                 :             : }
     655                 :             : 
     656                 :             : /*
     657                 :             :  * Interpret the fgc_flags and issue a suitable detail or hint message.
     658                 :             :  */
     659                 :             : static int
     660                 :          82 : oper_lookup_failure_details(int fgc_flags, bool is_unary_op)
     661                 :             : {
     662                 :             :     /*
     663                 :             :      * If not FGC_NAME_VISIBLE, we shouldn't raise the question of whether the
     664                 :             :      * arguments are wrong.  If the operator name was not schema-qualified,
     665                 :             :      * it's helpful to distinguish between doesn't-exist-anywhere and
     666                 :             :      * not-in-search-path; but if it was, there's really nothing to add to the
     667                 :             :      * basic "operator does not exist" message.
     668                 :             :      *
     669                 :             :      * Note: we passed missing_ok = false to OpernameGetCandidates, so there's
     670                 :             :      * no need to consider FGC_SCHEMA_EXISTS here: we'd have already thrown an
     671                 :             :      * error if an explicitly-given schema doesn't exist.
     672                 :             :      */
     673         [ +  + ]:          82 :     if (!(fgc_flags & FGC_NAME_VISIBLE))
     674                 :             :     {
     675         [ -  + ]:           8 :         if (fgc_flags & FGC_SCHEMA_GIVEN)
     676                 :           0 :             return 0;           /* schema-qualified name */
     677         [ +  + ]:           8 :         else if (!(fgc_flags & FGC_NAME_EXISTS))
     678                 :           4 :             return errdetail("There is no operator of that name.");
     679                 :             :         else
     680                 :           4 :             return errdetail("An operator of that name exists, but it is not in the search_path.");
     681                 :             :     }
     682                 :             : 
     683                 :             :     /*
     684                 :             :      * Otherwise, the problem must be incorrect argument type(s).
     685                 :             :      */
     686         [ +  + ]:          74 :     if (is_unary_op)
     687                 :             :     {
     688                 :           4 :         (void) errdetail("No operator of that name accepts the given argument type.");
     689                 :           4 :         return errhint("You might need to add an explicit type cast.");
     690                 :             :     }
     691                 :             :     else
     692                 :             :     {
     693                 :          70 :         (void) errdetail("No operator of that name accepts the given argument types.");
     694                 :          70 :         return errhint("You might need to add explicit type casts.");
     695                 :             :     }
     696                 :             : }
     697                 :             : 
     698                 :             : /*
     699                 :             :  * make_op()
     700                 :             :  *      Operator expression construction.
     701                 :             :  *
     702                 :             :  * Transform operator expression ensuring type compatibility.
     703                 :             :  * This is where some type conversion happens.
     704                 :             :  *
     705                 :             :  * last_srf should be a copy of pstate->p_last_srf from just before we
     706                 :             :  * started transforming the operator's arguments; this is used for nested-SRF
     707                 :             :  * detection.  If the caller will throw an error anyway for a set-returning
     708                 :             :  * expression, it's okay to cheat and just pass pstate->p_last_srf.
     709                 :             :  */
     710                 :             : Expr *
     711                 :      396717 : make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
     712                 :             :         Node *last_srf, int location)
     713                 :             : {
     714                 :             :     Oid         ltypeId,
     715                 :             :                 rtypeId;
     716                 :             :     Operator    tup;
     717                 :             :     Form_pg_operator opform;
     718                 :             :     Oid         actual_arg_types[2];
     719                 :             :     Oid         declared_arg_types[2];
     720                 :             :     int         nargs;
     721                 :             :     List       *args;
     722                 :             :     Oid         rettype;
     723                 :             :     OpExpr     *result;
     724                 :             : 
     725                 :             :     /* Check it's not a postfix operator */
     726         [ -  + ]:      396717 :     if (rtree == NULL)
     727         [ #  # ]:           0 :         ereport(ERROR,
     728                 :             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     729                 :             :                  errmsg("postfix operators are not supported")));
     730                 :             : 
     731                 :             :     /* Select the operator */
     732         [ +  + ]:      396717 :     if (ltree == NULL)
     733                 :             :     {
     734                 :             :         /* prefix operator */
     735                 :         821 :         rtypeId = exprType(rtree);
     736                 :         821 :         ltypeId = InvalidOid;
     737                 :         821 :         tup = left_oper(pstate, opname, rtypeId, false, location);
     738                 :             :     }
     739                 :             :     else
     740                 :             :     {
     741                 :             :         /* otherwise, binary operator */
     742                 :      395896 :         ltypeId = exprType(ltree);
     743                 :      395896 :         rtypeId = exprType(rtree);
     744                 :      395896 :         tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
     745                 :             :     }
     746                 :             : 
     747                 :      396631 :     opform = (Form_pg_operator) GETSTRUCT(tup);
     748                 :             : 
     749                 :             :     /* Check it's not a shell */
     750         [ -  + ]:      396631 :     if (!RegProcedureIsValid(opform->oprcode))
     751         [ #  # ]:           0 :         ereport(ERROR,
     752                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     753                 :             :                  errmsg("operator is only a shell: %s",
     754                 :             :                         op_signature_string(opname,
     755                 :             :                                             opform->oprleft,
     756                 :             :                                             opform->oprright)),
     757                 :             :                  parser_errposition(pstate, location)));
     758                 :             : 
     759                 :             :     /* Do typecasting and build the expression tree */
     760         [ +  + ]:      396631 :     if (ltree == NULL)
     761                 :             :     {
     762                 :             :         /* prefix operator */
     763                 :         809 :         args = list_make1(rtree);
     764                 :         809 :         actual_arg_types[0] = rtypeId;
     765                 :         809 :         declared_arg_types[0] = opform->oprright;
     766                 :         809 :         nargs = 1;
     767                 :             :     }
     768                 :             :     else
     769                 :             :     {
     770                 :             :         /* otherwise, binary operator */
     771                 :      395822 :         args = list_make2(ltree, rtree);
     772                 :      395822 :         actual_arg_types[0] = ltypeId;
     773                 :      395822 :         actual_arg_types[1] = rtypeId;
     774                 :      395822 :         declared_arg_types[0] = opform->oprleft;
     775                 :      395822 :         declared_arg_types[1] = opform->oprright;
     776                 :      395822 :         nargs = 2;
     777                 :             :     }
     778                 :             : 
     779                 :             :     /*
     780                 :             :      * enforce consistency with polymorphic argument and return types,
     781                 :             :      * possibly adjusting return type or declared_arg_types (which will be
     782                 :             :      * used as the cast destination by make_fn_arguments)
     783                 :             :      */
     784                 :      396631 :     rettype = enforce_generic_type_consistency(actual_arg_types,
     785                 :             :                                                declared_arg_types,
     786                 :             :                                                nargs,
     787                 :             :                                                opform->oprresult,
     788                 :             :                                                false);
     789                 :             : 
     790                 :             :     /* perform the necessary typecasting of arguments */
     791                 :      396631 :     make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
     792                 :             : 
     793                 :             :     /* and build the expression node */
     794                 :      396627 :     result = makeNode(OpExpr);
     795                 :      396627 :     result->opno = oprid(tup);
     796                 :      396627 :     result->opfuncid = opform->oprcode;
     797                 :      396627 :     result->opresulttype = rettype;
     798                 :      396627 :     result->opretset = get_func_retset(opform->oprcode);
     799                 :             :     /* opcollid and inputcollid will be set by parse_collate.c */
     800                 :      396627 :     result->args = args;
     801                 :      396627 :     result->location = location;
     802                 :             : 
     803                 :             :     /* if it returns a set, check that's OK */
     804         [ +  + ]:      396627 :     if (result->opretset)
     805                 :             :     {
     806                 :           4 :         check_srf_call_placement(pstate, last_srf, location);
     807                 :             :         /* ... and remember it for error checks at higher levels */
     808                 :           4 :         pstate->p_last_srf = (Node *) result;
     809                 :             :     }
     810                 :             : 
     811                 :      396627 :     ReleaseSysCache(tup);
     812                 :             : 
     813                 :      396627 :     return (Expr *) result;
     814                 :             : }
     815                 :             : 
     816                 :             : /*
     817                 :             :  * make_scalar_array_op()
     818                 :             :  *      Build expression tree for "scalar op ANY/ALL (array)" construct.
     819                 :             :  */
     820                 :             : Expr *
     821                 :       21971 : make_scalar_array_op(ParseState *pstate, List *opname,
     822                 :             :                      bool useOr,
     823                 :             :                      Node *ltree, Node *rtree,
     824                 :             :                      int location)
     825                 :             : {
     826                 :             :     Oid         ltypeId,
     827                 :             :                 rtypeId,
     828                 :             :                 atypeId,
     829                 :             :                 res_atypeId;
     830                 :             :     Operator    tup;
     831                 :             :     Form_pg_operator opform;
     832                 :             :     Oid         actual_arg_types[2];
     833                 :             :     Oid         declared_arg_types[2];
     834                 :             :     List       *args;
     835                 :             :     Oid         rettype;
     836                 :             :     ScalarArrayOpExpr *result;
     837                 :             : 
     838                 :       21971 :     ltypeId = exprType(ltree);
     839                 :       21971 :     atypeId = exprType(rtree);
     840                 :             : 
     841                 :             :     /*
     842                 :             :      * The right-hand input of the operator will be the element type of the
     843                 :             :      * array.  However, if we currently have just an untyped literal on the
     844                 :             :      * right, stay with that and hope we can resolve the operator.
     845                 :             :      */
     846         [ +  + ]:       21971 :     if (atypeId == UNKNOWNOID)
     847                 :         148 :         rtypeId = UNKNOWNOID;
     848                 :             :     else
     849                 :             :     {
     850                 :       21823 :         rtypeId = get_base_element_type(atypeId);
     851         [ +  + ]:       21823 :         if (!OidIsValid(rtypeId))
     852         [ +  - ]:           4 :             ereport(ERROR,
     853                 :             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     854                 :             :                      errmsg("op ANY/ALL (array) requires array on right side"),
     855                 :             :                      parser_errposition(pstate, location)));
     856                 :             :     }
     857                 :             : 
     858                 :             :     /* Now resolve the operator */
     859                 :       21967 :     tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
     860                 :       21967 :     opform = (Form_pg_operator) GETSTRUCT(tup);
     861                 :             : 
     862                 :             :     /* Check it's not a shell */
     863         [ -  + ]:       21967 :     if (!RegProcedureIsValid(opform->oprcode))
     864         [ #  # ]:           0 :         ereport(ERROR,
     865                 :             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     866                 :             :                  errmsg("operator is only a shell: %s",
     867                 :             :                         op_signature_string(opname,
     868                 :             :                                             opform->oprleft,
     869                 :             :                                             opform->oprright)),
     870                 :             :                  parser_errposition(pstate, location)));
     871                 :             : 
     872                 :       21967 :     args = list_make2(ltree, rtree);
     873                 :       21967 :     actual_arg_types[0] = ltypeId;
     874                 :       21967 :     actual_arg_types[1] = rtypeId;
     875                 :       21967 :     declared_arg_types[0] = opform->oprleft;
     876                 :       21967 :     declared_arg_types[1] = opform->oprright;
     877                 :             : 
     878                 :             :     /*
     879                 :             :      * enforce consistency with polymorphic argument and return types,
     880                 :             :      * possibly adjusting return type or declared_arg_types (which will be
     881                 :             :      * used as the cast destination by make_fn_arguments)
     882                 :             :      */
     883                 :       21967 :     rettype = enforce_generic_type_consistency(actual_arg_types,
     884                 :             :                                                declared_arg_types,
     885                 :             :                                                2,
     886                 :             :                                                opform->oprresult,
     887                 :             :                                                false);
     888                 :             : 
     889                 :             :     /*
     890                 :             :      * Check that operator result is boolean
     891                 :             :      */
     892         [ +  + ]:       21967 :     if (rettype != BOOLOID)
     893         [ +  - ]:           4 :         ereport(ERROR,
     894                 :             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     895                 :             :                  errmsg("op ANY/ALL (array) requires operator to yield boolean"),
     896                 :             :                  parser_errposition(pstate, location)));
     897         [ -  + ]:       21963 :     if (get_func_retset(opform->oprcode))
     898         [ #  # ]:           0 :         ereport(ERROR,
     899                 :             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     900                 :             :                  errmsg("op ANY/ALL (array) requires operator not to return a set"),
     901                 :             :                  parser_errposition(pstate, location)));
     902                 :             : 
     903                 :             :     /*
     904                 :             :      * Now switch back to the array type on the right, arranging for any
     905                 :             :      * needed cast to be applied.  Beware of polymorphic operators here;
     906                 :             :      * enforce_generic_type_consistency may or may not have replaced a
     907                 :             :      * polymorphic type with a real one.
     908                 :             :      */
     909   [ +  -  +  -  :       21963 :     if (IsPolymorphicType(declared_arg_types[1]))
          +  -  +  +  +  
          +  +  -  +  -  
          +  -  +  -  +  
                -  -  + ]
     910                 :             :     {
     911                 :             :         /* assume the actual array type is OK */
     912                 :          46 :         res_atypeId = atypeId;
     913                 :             :     }
     914                 :             :     else
     915                 :             :     {
     916                 :       21917 :         res_atypeId = get_array_type(declared_arg_types[1]);
     917         [ -  + ]:       21917 :         if (!OidIsValid(res_atypeId))
     918         [ #  # ]:           0 :             ereport(ERROR,
     919                 :             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     920                 :             :                      errmsg("could not find array type for data type %s",
     921                 :             :                             format_type_be(declared_arg_types[1])),
     922                 :             :                      parser_errposition(pstate, location)));
     923                 :             :     }
     924                 :       21963 :     actual_arg_types[1] = atypeId;
     925                 :       21963 :     declared_arg_types[1] = res_atypeId;
     926                 :             : 
     927                 :             :     /* perform the necessary typecasting of arguments */
     928                 :       21963 :     make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
     929                 :             : 
     930                 :             :     /* and build the expression node */
     931                 :       21963 :     result = makeNode(ScalarArrayOpExpr);
     932                 :       21963 :     result->opno = oprid(tup);
     933                 :       21963 :     result->opfuncid = opform->oprcode;
     934                 :       21963 :     result->hashfuncid = InvalidOid;
     935                 :       21963 :     result->negfuncid = InvalidOid;
     936                 :       21963 :     result->useOr = useOr;
     937                 :             :     /* inputcollid will be set by parse_collate.c */
     938                 :       21963 :     result->args = args;
     939                 :       21963 :     result->location = location;
     940                 :             : 
     941                 :       21963 :     ReleaseSysCache(tup);
     942                 :             : 
     943                 :       21963 :     return (Expr *) result;
     944                 :             : }
     945                 :             : 
     946                 :             : 
     947                 :             : /*
     948                 :             :  * Lookaside cache to speed operator lookup.  Possibly this should be in
     949                 :             :  * a separate module under utils/cache/ ?
     950                 :             :  *
     951                 :             :  * The idea here is that the mapping from operator name and given argument
     952                 :             :  * types is constant for a given search path (or single specified schema OID)
     953                 :             :  * so long as the contents of pg_operator and pg_cast don't change.  And that
     954                 :             :  * mapping is pretty expensive to compute, especially for ambiguous operators;
     955                 :             :  * this is mainly because there are a *lot* of instances of popular operator
     956                 :             :  * names such as "=", and we have to check each one to see which is the
     957                 :             :  * best match.  So once we have identified the correct mapping, we save it
     958                 :             :  * in a cache that need only be flushed on pg_operator or pg_cast change.
     959                 :             :  * (pg_cast must be considered because changes in the set of implicit casts
     960                 :             :  * affect the set of applicable operators for any given input datatype.)
     961                 :             :  *
     962                 :             :  * XXX in principle, ALTER TABLE ... INHERIT could affect the mapping as
     963                 :             :  * well, but we disregard that since there's no convenient way to find out
     964                 :             :  * about it, and it seems a pretty far-fetched corner-case anyway.
     965                 :             :  *
     966                 :             :  * Note: at some point it might be worth doing a similar cache for function
     967                 :             :  * lookups.  However, the potential gain is a lot less since (a) function
     968                 :             :  * names are generally not overloaded as heavily as operator names, and
     969                 :             :  * (b) we'd have to flush on pg_proc updates, which are probably a good
     970                 :             :  * deal more common than pg_operator updates.
     971                 :             :  */
     972                 :             : 
     973                 :             : /* The operator cache hashtable */
     974                 :             : static HTAB *OprCacheHash = NULL;
     975                 :             : 
     976                 :             : 
     977                 :             : /*
     978                 :             :  * make_oper_cache_key
     979                 :             :  *      Fill the lookup key struct given operator name and arg types.
     980                 :             :  *
     981                 :             :  * Returns true if successful, false if the search_path overflowed
     982                 :             :  * (hence no caching is possible).
     983                 :             :  *
     984                 :             :  * pstate/location are used only to report the error position; pass NULL/-1
     985                 :             :  * if not available.
     986                 :             :  */
     987                 :             : static bool
     988                 :      462785 : make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname,
     989                 :             :                     Oid ltypeId, Oid rtypeId, int location)
     990                 :             : {
     991                 :             :     char       *schemaname;
     992                 :             :     char       *opername;
     993                 :             : 
     994                 :             :     /* deconstruct the name list */
     995                 :      462785 :     DeconstructQualifiedName(opname, &schemaname, &opername);
     996                 :             : 
     997                 :             :     /* ensure zero-fill for stable hashing */
     998   [ +  -  +  -  :     8330130 :     MemSet(key, 0, sizeof(OprCacheKey));
          +  -  +  -  +  
                      + ]
     999                 :             : 
    1000                 :             :     /* save operator name and input types into key */
    1001                 :      462785 :     strlcpy(key->oprname, opername, NAMEDATALEN);
    1002                 :      462785 :     key->left_arg = ltypeId;
    1003                 :      462785 :     key->right_arg = rtypeId;
    1004                 :             : 
    1005         [ +  + ]:      462785 :     if (schemaname)
    1006                 :             :     {
    1007                 :             :         ParseCallbackState pcbstate;
    1008                 :             : 
    1009                 :             :         /* search only in exact schema given */
    1010                 :        9760 :         setup_parser_errposition_callback(&pcbstate, pstate, location);
    1011                 :        9760 :         key->search_path[0] = LookupExplicitNamespace(schemaname, false);
    1012                 :        9760 :         cancel_parser_errposition_callback(&pcbstate);
    1013                 :             :     }
    1014                 :             :     else
    1015                 :             :     {
    1016                 :             :         /* get the active search path */
    1017         [ -  + ]:      453025 :         if (fetch_search_path_array(key->search_path,
    1018                 :             :                                     MAX_CACHED_PATH_LEN) > MAX_CACHED_PATH_LEN)
    1019                 :           0 :             return false;       /* oops, didn't fit */
    1020                 :             :     }
    1021                 :             : 
    1022                 :      462785 :     return true;
    1023                 :             : }
    1024                 :             : 
    1025                 :             : /*
    1026                 :             :  * find_oper_cache_entry
    1027                 :             :  *
    1028                 :             :  * Look for a cache entry matching the given key.  If found, return the
    1029                 :             :  * contained operator OID, else return InvalidOid.
    1030                 :             :  */
    1031                 :             : static Oid
    1032                 :      462785 : find_oper_cache_entry(OprCacheKey *key)
    1033                 :             : {
    1034                 :             :     OprCacheEntry *oprentry;
    1035                 :             : 
    1036         [ +  + ]:      462785 :     if (OprCacheHash == NULL)
    1037                 :             :     {
    1038                 :             :         /* First time through: initialize the hash table */
    1039                 :             :         HASHCTL     ctl;
    1040                 :             : 
    1041                 :        6093 :         ctl.keysize = sizeof(OprCacheKey);
    1042                 :        6093 :         ctl.entrysize = sizeof(OprCacheEntry);
    1043                 :        6093 :         OprCacheHash = hash_create("Operator lookup cache", 256,
    1044                 :             :                                    &ctl, HASH_ELEM | HASH_BLOBS);
    1045                 :             : 
    1046                 :             :         /* Arrange to flush cache on pg_operator and pg_cast changes */
    1047                 :        6093 :         CacheRegisterSyscacheCallback(OPERNAMENSP,
    1048                 :             :                                       InvalidateOprCacheCallBack,
    1049                 :             :                                       (Datum) 0);
    1050                 :        6093 :         CacheRegisterSyscacheCallback(CASTSOURCETARGET,
    1051                 :             :                                       InvalidateOprCacheCallBack,
    1052                 :             :                                       (Datum) 0);
    1053                 :             :     }
    1054                 :             : 
    1055                 :             :     /* Look for an existing entry */
    1056                 :      462785 :     oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
    1057                 :             :                                              key,
    1058                 :             :                                              HASH_FIND, NULL);
    1059         [ +  + ]:      462785 :     if (oprentry == NULL)
    1060                 :       49972 :         return InvalidOid;
    1061                 :             : 
    1062                 :      412813 :     return oprentry->opr_oid;
    1063                 :             : }
    1064                 :             : 
    1065                 :             : /*
    1066                 :             :  * make_oper_cache_entry
    1067                 :             :  *
    1068                 :             :  * Insert a cache entry for the given key.
    1069                 :             :  */
    1070                 :             : static void
    1071                 :       49881 : make_oper_cache_entry(OprCacheKey *key, Oid opr_oid)
    1072                 :             : {
    1073                 :             :     OprCacheEntry *oprentry;
    1074                 :             : 
    1075                 :             :     Assert(OprCacheHash != NULL);
    1076                 :             : 
    1077                 :       49881 :     oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
    1078                 :             :                                              key,
    1079                 :             :                                              HASH_ENTER, NULL);
    1080                 :       49881 :     oprentry->opr_oid = opr_oid;
    1081                 :       49881 : }
    1082                 :             : 
    1083                 :             : /*
    1084                 :             :  * Callback for pg_operator and pg_cast inval events
    1085                 :             :  */
    1086                 :             : static void
    1087                 :        7761 : InvalidateOprCacheCallBack(Datum arg, SysCacheIdentifier cacheid,
    1088                 :             :                            uint32 hashvalue)
    1089                 :             : {
    1090                 :             :     HASH_SEQ_STATUS status;
    1091                 :             :     OprCacheEntry *hentry;
    1092                 :             : 
    1093                 :             :     Assert(OprCacheHash != NULL);
    1094                 :             : 
    1095                 :             :     /* Currently we just flush all entries; hard to be smarter ... */
    1096                 :        7761 :     hash_seq_init(&status, OprCacheHash);
    1097                 :             : 
    1098         [ +  + ]:       20475 :     while ((hentry = (OprCacheEntry *) hash_seq_search(&status)) != NULL)
    1099                 :             :     {
    1100         [ -  + ]:       12714 :         if (hash_search(OprCacheHash,
    1101                 :       12714 :                         &hentry->key,
    1102                 :             :                         HASH_REMOVE, NULL) == NULL)
    1103         [ #  # ]:           0 :             elog(ERROR, "hash table corrupted");
    1104                 :             :     }
    1105                 :        7761 : }
        

Generated by: LCOV version 2.0-1