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