#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Go to the source code of this file.
Data Structures | |
struct | OprCacheKey |
struct | OprCacheEntry |
Defines | |
#define | MAX_CACHED_PATH_LEN 16 |
Typedefs | |
typedef struct OprCacheKey | OprCacheKey |
typedef struct OprCacheEntry | OprCacheEntry |
Functions | |
static Oid | binary_oper_exact (List *opname, Oid arg1, Oid arg2) |
static FuncDetailCode | oper_select_candidate (int nargs, Oid *input_typeids, FuncCandidateList candidates, Oid *operOid) |
static const char * | op_signature_string (List *op, char oprkind, Oid arg1, Oid arg2) |
static void | op_error (ParseState *pstate, List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult, int location) |
static bool | make_oper_cache_key (OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId) |
static Oid | find_oper_cache_entry (OprCacheKey *key) |
static void | make_oper_cache_entry (OprCacheKey *key, Oid opr_oid) |
static void | InvalidateOprCacheCallBack (Datum arg, int cacheid, uint32 hashvalue) |
Oid | LookupOperName (ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location) |
Oid | LookupOperNameTypeNames (ParseState *pstate, List *opername, TypeName *oprleft, TypeName *oprright, bool noError, int location) |
void | get_sort_group_operators (Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, bool *isHashable) |
Oid | oprid (Operator op) |
Oid | oprfuncid (Operator op) |
Operator | oper (ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location) |
Operator | compatible_oper (ParseState *pstate, List *op, Oid arg1, Oid arg2, bool noError, int location) |
Oid | compatible_oper_opid (List *op, Oid arg1, Oid arg2, bool noError) |
Operator | right_oper (ParseState *pstate, List *op, Oid arg, bool noError, int location) |
Operator | left_oper (ParseState *pstate, List *op, Oid arg, bool noError, int location) |
Expr * | make_op (ParseState *pstate, List *opname, Node *ltree, Node *rtree, int location) |
Expr * | make_scalar_array_op (ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location) |
Variables | |
static HTAB * | OprCacheHash = NULL |
#define MAX_CACHED_PATH_LEN 16 |
Definition at line 49 of file parse_oper.c.
Referenced by make_oper_cache_key().
typedef struct OprCacheEntry OprCacheEntry |
typedef struct OprCacheKey OprCacheKey |
Definition at line 266 of file parse_oper.c.
References getBaseType(), InvalidOid, OidIsValid, OpernameGetOprid(), and UNKNOWNOID.
Referenced by oper().
{ Oid result; bool was_unknown = false; /* Unspecified type for one of the arguments? then use the other */ if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid)) { arg1 = arg2; was_unknown = true; } else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid)) { arg2 = arg1; was_unknown = true; } result = OpernameGetOprid(opname, arg1, arg2); if (OidIsValid(result)) return result; if (was_unknown) { /* arg1 and arg2 are the same here, need only look at arg1 */ Oid basetype = getBaseType(arg1); if (basetype != arg1) { result = OpernameGetOprid(opname, basetype, basetype); if (OidIsValid(result)) return result; } } return InvalidOid; }
Operator compatible_oper | ( | ParseState * | pstate, | |
List * | op, | |||
Oid | arg1, | |||
Oid | arg2, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 453 of file parse_oper.c.
References ereport, errcode(), errmsg(), ERROR, GETSTRUCT, IsBinaryCoercible(), NULL, op_signature_string(), oper(), parser_errposition(), and ReleaseSysCache().
Referenced by compatible_oper_opid().
{ Operator optup; Form_pg_operator opform; /* oper() will find the best available match */ optup = oper(pstate, op, arg1, arg2, noError, location); if (optup == (Operator) NULL) return (Operator) NULL; /* must be noError case */ /* but is it good enough? */ opform = (Form_pg_operator) GETSTRUCT(optup); if (IsBinaryCoercible(arg1, opform->oprleft) && IsBinaryCoercible(arg2, opform->oprright)) return optup; /* nope... */ ReleaseSysCache(optup); if (!noError) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator requires run-time type coercion: %s", op_signature_string(op, 'b', arg1, arg2)), parser_errposition(pstate, location))); return (Operator) NULL; }
Definition at line 490 of file parse_oper.c.
References compatible_oper(), NULL, oprid(), and ReleaseSysCache().
Referenced by addTargetToSortList(), and ComputeIndexAttrs().
{ Operator optup; Oid result; optup = compatible_oper(NULL, op, arg1, arg2, noError, -1); if (optup != NULL) { result = oprid(optup); ReleaseSysCache(optup); return result; } return InvalidOid; }
static Oid find_oper_cache_entry | ( | OprCacheKey * | key | ) | [static] |
Definition at line 1050 of file parse_oper.c.
References CacheRegisterSyscacheCallback(), CASTSOURCETARGET, HASHCTL::entrysize, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), InvalidateOprCacheCallBack(), HASHCTL::keysize, MemSet, NULL, OPERNAMENSP, and OprCacheEntry::opr_oid.
Referenced by left_oper(), oper(), and right_oper().
{ OprCacheEntry *oprentry; if (OprCacheHash == NULL) { /* First time through: initialize the hash table */ HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(OprCacheKey); ctl.entrysize = sizeof(OprCacheEntry); ctl.hash = tag_hash; OprCacheHash = hash_create("Operator lookup cache", 256, &ctl, HASH_ELEM | HASH_FUNCTION); /* Arrange to flush cache on pg_operator and pg_cast changes */ CacheRegisterSyscacheCallback(OPERNAMENSP, InvalidateOprCacheCallBack, (Datum) 0); CacheRegisterSyscacheCallback(CASTSOURCETARGET, InvalidateOprCacheCallBack, (Datum) 0); } /* Look for an existing entry */ oprentry = (OprCacheEntry *) hash_search(OprCacheHash, (void *) key, HASH_FIND, NULL); if (oprentry == NULL) return InvalidOid; return oprentry->opr_oid; }
void get_sort_group_operators | ( | Oid | argtype, | |
bool | needLT, | |||
bool | needEQ, | |||
bool | needGT, | |||
Oid * | ltOpr, | |||
Oid * | eqOpr, | |||
Oid * | gtOpr, | |||
bool * | isHashable | |||
) |
Definition at line 184 of file parse_oper.c.
References TypeCacheEntry::eq_opr, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), TypeCacheEntry::gt_opr, TypeCacheEntry::hash_proc, lookup_type_cache(), TypeCacheEntry::lt_opr, NULL, OidIsValid, TYPECACHE_EQ_OPR, TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.
Referenced by addTargetToGroupList(), addTargetToSortList(), std_typanalyze(), and transformSetOperationTree().
{ TypeCacheEntry *typentry; int cache_flags; Oid lt_opr; Oid eq_opr; Oid gt_opr; bool hashable; /* * Look up the operators using the type cache. * * Note: the search algorithm used by typcache.c ensures that the results * are consistent, ie all from matching opclasses. */ if (isHashable != NULL) cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR | TYPECACHE_HASH_PROC; else cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR; typentry = lookup_type_cache(argtype, cache_flags); lt_opr = typentry->lt_opr; eq_opr = typentry->eq_opr; gt_opr = typentry->gt_opr; hashable = OidIsValid(typentry->hash_proc); /* Report errors if needed */ if ((needLT && !OidIsValid(lt_opr)) || (needGT && !OidIsValid(gt_opr))) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an ordering operator for type %s", format_type_be(argtype)), errhint("Use an explicit ordering operator or modify the query."))); if (needEQ && !OidIsValid(eq_opr)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an equality operator for type %s", format_type_be(argtype)))); /* Return results as needed */ if (ltOpr) *ltOpr = lt_opr; if (eqOpr) *eqOpr = eq_opr; if (gtOpr) *gtOpr = gt_opr; if (isHashable) *isHashable = hashable; }
Definition at line 1107 of file parse_oper.c.
References Assert, elog, ERROR, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), OprCacheEntry::key, and NULL.
Referenced by find_oper_cache_entry().
{ HASH_SEQ_STATUS status; OprCacheEntry *hentry; Assert(OprCacheHash != NULL); /* Currently we just flush all entries; hard to be smarter ... */ hash_seq_init(&status, OprCacheHash); while ((hentry = (OprCacheEntry *) hash_seq_search(&status)) != NULL) { if (hash_search(OprCacheHash, (void *) &hentry->key, HASH_REMOVE, NULL) == NULL) elog(ERROR, "hash table corrupted"); } }
Operator left_oper | ( | ParseState * | pstate, | |
List * | op, | |||
Oid | arg, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 599 of file parse_oper.c.
References _FuncCandidateList::args, find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), _FuncCandidateList::next, NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OpernameGetOprid(), OPEROID, and SearchSysCache1.
Referenced by generate_operator_name(), and make_op().
{ Oid operOid; OprCacheKey key; bool key_ok; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* * Try to find the mapping in the lookaside cache. */ key_ok = make_oper_cache_key(&key, op, InvalidOid, arg); if (key_ok) { operOid = find_oper_cache_entry(&key); if (OidIsValid(operOid)) { tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) return (Operator) tup; } } /* * First try for an "exact" match. */ operOid = OpernameGetOprid(op, InvalidOid, arg); if (!OidIsValid(operOid)) { /* * Otherwise, search for the most suitable candidate. */ FuncCandidateList clist; /* Get prefix operators of given name */ clist = OpernameGetCandidates(op, 'l'); /* No operators found? Then fail... */ if (clist != NULL) { /* * The returned list has args in the form (0, oprright). Move the * useful data into args[0] to keep oper_select_candidate simple. * XXX we are assuming here that we may scribble on the list! */ FuncCandidateList clisti; for (clisti = clist; clisti != NULL; clisti = clisti->next) { clisti->args[0] = clisti->args[1]; } /* * We must run oper_select_candidate even if only one candidate, * otherwise we may falsely return a non-type-compatible operator. */ fdresult = oper_select_candidate(1, &arg, clist, &operOid); } } if (OidIsValid(operOid)) tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) { if (key_ok) make_oper_cache_entry(&key, operOid); } else if (!noError) op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location); return (Operator) tup; }
Oid LookupOperName | ( | ParseState * | pstate, | |
List * | opername, | |||
Oid | oprleft, | |||
Oid | oprright, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 101 of file parse_oper.c.
References ereport, errcode(), errmsg(), ERROR, OidIsValid, op_signature_string(), OpernameGetOprid(), and parser_errposition().
Referenced by AggregateCreate(), DefineOpClass(), and LookupOperNameTypeNames().
{ Oid result; result = OpernameGetOprid(opername, oprleft, oprright); if (OidIsValid(result)) return result; /* we don't use op_error here because only an exact match is wanted */ if (!noError) { char oprkind; if (!OidIsValid(oprleft)) oprkind = 'l'; else if (!OidIsValid(oprright)) oprkind = 'r'; else oprkind = 'b'; ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", op_signature_string(opername, oprkind, oprleft, oprright)), parser_errposition(pstate, location))); } return InvalidOid; }
Oid LookupOperNameTypeNames | ( | ParseState * | pstate, | |
List * | opername, | |||
TypeName * | oprleft, | |||
TypeName * | oprright, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 141 of file parse_oper.c.
References LookupOperName(), NULL, and typenameTypeId().
Referenced by AlterOpFamilyAdd(), DefineOpClass(), and get_object_address().
{ Oid leftoid, rightoid; if (oprleft == NULL) leftoid = InvalidOid; else leftoid = typenameTypeId(pstate, oprleft); if (oprright == NULL) rightoid = InvalidOid; else rightoid = typenameTypeId(pstate, oprright); return LookupOperName(pstate, opername, leftoid, rightoid, noError, location); }
Expr* make_op | ( | ParseState * | pstate, | |
List * | opname, | |||
Node * | ltree, | |||
Node * | rtree, | |||
int | location | |||
) |
Definition at line 736 of file parse_oper.c.
References OpExpr::args, enforce_generic_type_consistency(), ereport, errcode(), errmsg(), ERROR, exprType(), get_func_retset(), GETSTRUCT, left_oper(), list_make1, list_make2, OpExpr::location, make_fn_arguments(), makeNode, NULL, op_signature_string(), oper(), OpExpr::opfuncid, OpExpr::opno, OpExpr::opresulttype, OpExpr::opretset, oprid(), parser_errposition(), RegProcedureIsValid, ReleaseSysCache(), and right_oper().
Referenced by make_distinct_op(), make_row_comparison_op(), transformAExprIn(), transformAExprNullIf(), and transformAExprOp().
{ Oid ltypeId, rtypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; int nargs; List *args; Oid rettype; OpExpr *result; /* Select the operator */ if (rtree == NULL) { /* right operator */ ltypeId = exprType(ltree); rtypeId = InvalidOid; tup = right_oper(pstate, opname, ltypeId, false, location); } else if (ltree == NULL) { /* left operator */ rtypeId = exprType(rtree); ltypeId = InvalidOid; tup = left_oper(pstate, opname, rtypeId, false, location); } else { /* otherwise, binary operator */ ltypeId = exprType(ltree); rtypeId = exprType(rtree); tup = oper(pstate, opname, ltypeId, rtypeId, false, location); } opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); /* Do typecasting and build the expression tree */ if (rtree == NULL) { /* right operator */ args = list_make1(ltree); actual_arg_types[0] = ltypeId; declared_arg_types[0] = opform->oprleft; nargs = 1; } else if (ltree == NULL) { /* left operator */ args = list_make1(rtree); actual_arg_types[0] = rtypeId; declared_arg_types[0] = opform->oprright; nargs = 1; } else { /* otherwise, binary operator */ args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; nargs = 2; } /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, nargs, opform->oprresult, false); /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(OpExpr); result->opno = oprid(tup); result->opfuncid = opform->oprcode; result->opresulttype = rettype; result->opretset = get_func_retset(opform->oprcode); /* opcollid and inputcollid will be set by parse_collate.c */ result->args = args; result->location = location; ReleaseSysCache(tup); return (Expr *) result; }
static void make_oper_cache_entry | ( | OprCacheKey * | key, | |
Oid | opr_oid | |||
) | [static] |
Definition at line 1091 of file parse_oper.c.
References Assert, hash_search(), NULL, and OprCacheEntry::opr_oid.
Referenced by left_oper(), oper(), and right_oper().
{ OprCacheEntry *oprentry; Assert(OprCacheHash != NULL); oprentry = (OprCacheEntry *) hash_search(OprCacheHash, (void *) key, HASH_ENTER, NULL); oprentry->opr_oid = opr_oid; }
static bool make_oper_cache_key | ( | OprCacheKey * | key, | |
List * | opname, | |||
Oid | ltypeId, | |||
Oid | rtypeId | |||
) | [static] |
Definition at line 1011 of file parse_oper.c.
References DeconstructQualifiedName(), fetch_search_path_array(), OprCacheKey::left_arg, LookupExplicitNamespace(), MAX_CACHED_PATH_LEN, MemSet, NAMEDATALEN, OprCacheKey::oprname, OprCacheKey::right_arg, OprCacheKey::search_path, and strlcpy().
Referenced by left_oper(), oper(), and right_oper().
{ char *schemaname; char *opername; /* deconstruct the name list */ DeconstructQualifiedName(opname, &schemaname, &opername); /* ensure zero-fill for stable hashing */ MemSet(key, 0, sizeof(OprCacheKey)); /* save operator name and input types into key */ strlcpy(key->oprname, opername, NAMEDATALEN); key->left_arg = ltypeId; key->right_arg = rtypeId; if (schemaname) { /* search only in exact schema given */ key->search_path[0] = LookupExplicitNamespace(schemaname, false); } else { /* get the active search path */ if (fetch_search_path_array(key->search_path, MAX_CACHED_PATH_LEN) > MAX_CACHED_PATH_LEN) return false; /* oops, didn't fit */ } return true; }
Expr* make_scalar_array_op | ( | ParseState * | pstate, | |
List * | opname, | |||
bool | useOr, | |||
Node * | ltree, | |||
Node * | rtree, | |||
int | location | |||
) |
Definition at line 848 of file parse_oper.c.
References ScalarArrayOpExpr::args, BOOLOID, enforce_generic_type_consistency(), ereport, errcode(), errmsg(), ERROR, exprType(), format_type_be(), get_array_type(), get_base_element_type(), get_func_retset(), GETSTRUCT, IsPolymorphicType, list_make2, ScalarArrayOpExpr::location, make_fn_arguments(), makeNode, OidIsValid, op_signature_string(), oper(), ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, oprid(), parser_errposition(), RegProcedureIsValid, ReleaseSysCache(), UNKNOWNOID, and ScalarArrayOpExpr::useOr.
Referenced by transformAExprIn(), transformAExprOpAll(), and transformAExprOpAny().
{ Oid ltypeId, rtypeId, atypeId, res_atypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; List *args; Oid rettype; ScalarArrayOpExpr *result; ltypeId = exprType(ltree); atypeId = exprType(rtree); /* * The right-hand input of the operator will be the element type of the * array. However, if we currently have just an untyped literal on the * right, stay with that and hope we can resolve the operator. */ if (atypeId == UNKNOWNOID) rtypeId = UNKNOWNOID; else { rtypeId = get_base_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"), parser_errposition(pstate, location))); } /* Now resolve the operator */ tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, 2, opform->oprresult, false); /* * Check that operator result is boolean */ if (rettype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator to yield boolean"), parser_errposition(pstate, location))); if (get_func_retset(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator not to return a set"), parser_errposition(pstate, location))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. Beware of polymorphic operators here; * enforce_generic_type_consistency may or may not have replaced a * polymorphic type with a real one. */ if (IsPolymorphicType(declared_arg_types[1])) { /* assume the actual array type is OK */ res_atypeId = atypeId; } else { res_atypeId = get_array_type(declared_arg_types[1]); if (!OidIsValid(res_atypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(declared_arg_types[1])), parser_errposition(pstate, location))); } actual_arg_types[1] = atypeId; declared_arg_types[1] = res_atypeId; /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(ScalarArrayOpExpr); result->opno = oprid(tup); result->opfuncid = opform->oprcode; result->useOr = useOr; /* inputcollid will be set by parse_collate.c */ result->args = args; result->location = location; ReleaseSysCache(tup); return (Expr *) result; }
static void op_error | ( | ParseState * | pstate, | |
List * | op, | |||
char | oprkind, | |||
Oid | arg1, | |||
Oid | arg2, | |||
FuncDetailCode | fdresult, | |||
int | location | |||
) | [static] |
Definition at line 703 of file parse_oper.c.
References ereport, errcode(), errhint(), errmsg(), ERROR, FUNCDETAIL_MULTIPLE, op_signature_string(), and parser_errposition().
Referenced by left_oper(), oper(), and right_oper().
{ if (fdresult == FUNCDETAIL_MULTIPLE) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("operator is not unique: %s", op_signature_string(op, oprkind, arg1, arg2)), errhint("Could not choose a best candidate operator. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", op_signature_string(op, oprkind, arg1, arg2)), errhint("No operator matches the given name and argument type(s). " "You might need to add explicit type casts."), parser_errposition(pstate, location))); }
Definition at line 682 of file parse_oper.c.
References appendStringInfo(), appendStringInfoString(), StringInfoData::data, format_type_be(), initStringInfo(), and NameListToString().
Referenced by compatible_oper(), LookupOperName(), make_op(), make_scalar_array_op(), and op_error().
{ StringInfoData argbuf; initStringInfo(&argbuf); if (oprkind != 'l') appendStringInfo(&argbuf, "%s ", format_type_be(arg1)); appendStringInfoString(&argbuf, NameListToString(op)); if (oprkind != 'r') appendStringInfo(&argbuf, " %s", format_type_be(arg2)); return argbuf.data; /* return palloc'd string buffer */ }
Operator oper | ( | ParseState * | pstate, | |
List * | opname, | |||
Oid | ltypeId, | |||
Oid | rtypeId, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 374 of file parse_oper.c.
References binary_oper_exact(), find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OPEROID, and SearchSysCache1.
Referenced by compatible_oper(), generate_operator_name(), make_op(), make_scalar_array_op(), makeOperatorDependencies(), and tsquery_opr_selec().
{ Oid operOid; OprCacheKey key; bool key_ok; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* * Try to find the mapping in the lookaside cache. */ key_ok = make_oper_cache_key(&key, opname, ltypeId, rtypeId); if (key_ok) { operOid = find_oper_cache_entry(&key); if (OidIsValid(operOid)) { tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) return (Operator) tup; } } /* * First try for an "exact" match. */ operOid = binary_oper_exact(opname, ltypeId, rtypeId); if (!OidIsValid(operOid)) { /* * Otherwise, search for the most suitable candidate. */ FuncCandidateList clist; /* Get binary operators of given name */ clist = OpernameGetCandidates(opname, 'b'); /* No operators found? Then fail... */ if (clist != NULL) { /* * Unspecified type for one of the arguments? then use the other * (XXX this is probably dead code?) */ Oid inputOids[2]; if (rtypeId == InvalidOid) rtypeId = ltypeId; else if (ltypeId == InvalidOid) ltypeId = rtypeId; inputOids[0] = ltypeId; inputOids[1] = rtypeId; fdresult = oper_select_candidate(2, inputOids, clist, &operOid); } } if (OidIsValid(operOid)) tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) { if (key_ok) make_oper_cache_entry(&key, operOid); } else if (!noError) op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location); return (Operator) tup; }
static FuncDetailCode oper_select_candidate | ( | int | nargs, | |
Oid * | input_typeids, | |||
FuncCandidateList | candidates, | |||
Oid * | operOid | |||
) | [static] |
Definition at line 316 of file parse_oper.c.
References func_match_argtypes(), func_select_candidate(), and _FuncCandidateList::oid.
Referenced by left_oper(), oper(), and right_oper().
{ int ncandidates; /* * Delete any candidates that cannot actually accept the given input * types, whether directly or by coercion. */ ncandidates = func_match_argtypes(nargs, input_typeids, candidates, &candidates); /* Done if no candidate or only one candidate survives */ if (ncandidates == 0) { *operOid = InvalidOid; return FUNCDETAIL_NOTFOUND; } if (ncandidates == 1) { *operOid = candidates->oid; return FUNCDETAIL_NORMAL; } /* * Use the same heuristics as for ambiguous functions to resolve the * conflict. */ candidates = func_select_candidate(nargs, input_typeids, candidates); if (candidates) { *operOid = candidates->oid; return FUNCDETAIL_NORMAL; } *operOid = InvalidOid; return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */ }
Definition at line 249 of file parse_oper.c.
References GETSTRUCT.
{ Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op); return pgopform->oprcode; }
Definition at line 242 of file parse_oper.c.
References HeapTupleGetOid.
Referenced by compatible_oper_opid(), generate_operator_name(), make_op(), make_scalar_array_op(), regoperatorout(), and regoperout().
{ return HeapTupleGetOid(op); }
Operator right_oper | ( | ParseState * | pstate, | |
List * | op, | |||
Oid | arg, | |||
bool | noError, | |||
int | location | |||
) |
Definition at line 521 of file parse_oper.c.
References find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OpernameGetOprid(), OPEROID, and SearchSysCache1.
Referenced by generate_operator_name(), and make_op().
{ Oid operOid; OprCacheKey key; bool key_ok; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* * Try to find the mapping in the lookaside cache. */ key_ok = make_oper_cache_key(&key, op, arg, InvalidOid); if (key_ok) { operOid = find_oper_cache_entry(&key); if (OidIsValid(operOid)) { tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) return (Operator) tup; } } /* * First try for an "exact" match. */ operOid = OpernameGetOprid(op, arg, InvalidOid); if (!OidIsValid(operOid)) { /* * Otherwise, search for the most suitable candidate. */ FuncCandidateList clist; /* Get postfix operators of given name */ clist = OpernameGetCandidates(op, 'r'); /* No operators found? Then fail... */ if (clist != NULL) { /* * We must run oper_select_candidate even if only one candidate, * otherwise we may falsely return a non-type-compatible operator. */ fdresult = oper_select_candidate(1, &arg, clist, &operOid); } } if (OidIsValid(operOid)) tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (HeapTupleIsValid(tup)) { if (key_ok) make_oper_cache_entry(&key, operOid); } else if (!noError) op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location); return (Operator) tup; }
HTAB* OprCacheHash = NULL [static] |
Definition at line 1000 of file parse_oper.c.