LCOV - code coverage report
Current view: top level - src/backend/parser - parse_oper.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 283 309 91.6 %
Date: 2019-11-21 13:06:38 Functions: 19 20 95.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13