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