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