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