/* If your search_path is longer than this, sucks to be you ... */ #define MAX_CACHED_PATH_LEN 16
typedefstruct OprCacheKey
{ char oprname[NAMEDATALEN];
Oid left_arg; /* Left input OID, or 0 if prefix op */
Oid right_arg; /* Right input OID */
Oid search_path[MAX_CACHED_PATH_LEN];
} OprCacheKey;
typedefstruct OprCacheEntry
{ /* the hash lookup key MUST BE FIRST */
OprCacheKey key;
Oid opr_oid; /* OID of the resolved operator */
} OprCacheEntry;
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); staticvoid op_error(ParseState *pstate, List *op,
Oid arg1, Oid arg2,
FuncDetailCode fdresult, int location); staticbool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
List *opname, Oid ltypeId, Oid rtypeId, int location); static Oid find_oper_cache_entry(OprCacheKey *key); staticvoid make_oper_cache_entry(OprCacheKey *key, Oid opr_oid); staticvoid InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
/* *LookupOperName *Givenapossibly-qualifiedoperatornameandexactinputdatatypes, *lookuptheoperator. * *Passoprleft=InvalidOidforaprefixop. * *Iftheoperatornameisnotschema-qualified,itissoughtinthecurrent *namespacesearchpath. * *Iftheoperatorisnotfound,wereturnInvalidOidifnoErroristrue, *elseraiseanerror.pstateandlocationareusedonlytoreportthe *errorposition;passNULL/-1ifnotavailable.
*/
Oid
LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
{
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)
{ if (!OidIsValid(oprright))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("postfix operators are not supported"),
parser_errposition(pstate, location)));
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s",
op_signature_string(opername, oprleft, oprright)),
parser_errposition(pstate, location)));
}
return InvalidOid;
}
/* *LookupOperWithArgs *LikeLookupOperName,buttheargumenttypesarespecifiedby *aObjectWithArgsnode.
*/
Oid
LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
{ TypeName *oprleft,
*oprright;
Oid leftoid,
rightoid;
/* 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;
}
/* given operator tuple, return the operator OID */
Oid
oprid(Operator op)
{ return ((Form_pg_operator) GETSTRUCT(op))->oid;
}
/* given operator tuple, return the underlying function's OID */
Oid
oprfuncid(Operator op)
{
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
return pgopform->oprcode;
}
/* binary_oper_exact() *Checkforan"exact"matchtothespecifiedoperandtypes. * *Ifoneoperandisanunknownliteral,assumeitshouldbetakentobe *thesametypeastheotheroperandforthispurpose.Also,consider *thepossibilitythattheotheroperandisadomaintypethatneedsto *bereducedtoitsbasetypetofindan"exact"match.
*/ static Oid
binary_oper_exact(List *opname, Oid arg1, Oid arg2)
{
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;
} elseif ((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;
}
/* oper_select_candidate() *Giventheinputargtypearrayandoneormorecandidates *fortheoperator,attempttoresolvetheconflict. * *ReturnsFUNCDETAIL_NOTFOUND,FUNCDETAIL_MULTIPLE,orFUNCDETAIL_NORMAL. *InthesuccesscasetheOidofthebestcandidateisstoredin*operOid. * *Notethatthecallerhasalreadydeterminedthatthereisnocandidate *exactlymatchingtheinputargtype(s).Incompatiblecandidatesarenotyet *prunedaway,however.
*/ static FuncDetailCode
oper_select_candidate(int nargs,
Oid *input_typeids,
FuncCandidateList candidates,
Oid *operOid) /* output argument */
{ int ncandidates;
/* 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;
}
/* Get binary operators of given name */
clist = OpernameGetCandidates(opname, 'b', false);
/* No operators found? Then fail... */ if (clist != NULL)
{ /* *Unspecifiedtypeforoneofthearguments?thenusetheother *(XXXthisisprobablydeadcode?)
*/
Oid inputOids[2];
if (OidIsValid(operOid))
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
if (HeapTupleIsValid(tup))
{ if (key_ok)
make_oper_cache_entry(&key, operOid);
} elseif (!noError)
op_error(pstate, opname, ltypeId, rtypeId, fdresult, location);
return (Operator) tup;
}
/* compatible_oper() *givenanopnameandinputdatatypes,findacompatiblebinaryoperator * *Thisistighterthanoper()becauseitwillnotreturnanoperatorthat *requirescoercionoftheinputdatatypes(butbinary-compatibleoperators *areaccepted).Otherwise,thesemanticsarethesame.
*/ Operator
compatible_oper(ParseState *pstate, List *op, Oid arg1, Oid arg2, bool noError, int location)
{ 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, arg1, arg2)),
parser_errposition(pstate, location)));
return (Operator) NULL;
}
/* compatible_oper_opid() -- get OID of a binary operator * *ThisisaconvenienceroutinethatextractsonlytheoperatorOID *fromtheresultofcompatible_oper().InvalidOidisreturnedifthe *lookupfailsandnoErroristrue.
*/
Oid
compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
{ Operator optup;
Oid result;
/* *op_error-utilityroutinetocomplainaboutanunresolvableoperator
*/ staticvoid
op_error(ParseState *pstate, List *op,
Oid arg1, Oid arg2,
FuncDetailCode fdresult, int location)
{ if (fdresult == FUNCDETAIL_MULTIPLE)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("operator is not unique: %s",
op_signature_string(op, 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, arg1, arg2)),
(!arg1 || !arg2) ?
errhint("No operator matches the given name and argument type. " "You might need to add an explicit type cast.") :
errhint("No operator matches the given name and argument types. " "You might need to add explicit type casts."),
parser_errposition(pstate, location)));
}
/* *make_op() *Operatorexpressionconstruction. * *Transformoperatorexpressionensuringtypecompatibility. *Thisiswheresometypeconversionhappens. * *last_srfshouldbeacopyofpstate->p_last_srffromjustbeforewe *startedtransformingtheoperator'sarguments;thisisusedfornested-SRF *detection.Ifthecallerwillthrowanerroranywayforaset-returning *expression,it'sokaytocheatandjustpasspstate->p_last_srf.
*/
Expr *
make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
Node *last_srf, int location)
{
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;
/* Check it's not a postfix operator */ if (rtree == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("postfix operators are not supported")));
/* 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->oprleft,
opform->oprright)),
parser_errposition(pstate, location)));
/* 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;
/* if it returns a set, check that's OK */ if (result->opretset)
{
check_srf_call_placement(pstate, last_srf, location); /* ... and remember it for error checks at higher levels */
pstate->p_last_srf = (Node *) result;
}
ReleaseSysCache(tup);
return (Expr *) result;
}
/* *make_scalar_array_op() *Buildexpressiontreefor"scalaropANY/ALL(array)"construct.
*/
Expr *
make_scalar_array_op(ParseState *pstate, List *opname, bool useOr,
Node *ltree, Node *rtree, int location)
{
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;
/* *Theright-handinputoftheoperatorwillbetheelementtypeofthe *array.However,ifwecurrentlyhavejustanuntypedliteralonthe *right,staywiththatandhopewecanresolvetheoperator.
*/ 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->oprleft,
opform->oprright)),
parser_errposition(pstate, location)));
/* *Checkthatoperatorresultisboolean
*/ 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)));
/* *Nowswitchbacktothearraytypeontheright,arrangingforany *neededcasttobeapplied.Bewareofpolymorphicoperatorshere; *enforce_generic_type_consistencymayormaynothavereplaceda *polymorphictypewitharealone.
*/ 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->hashfuncid = InvalidOid;
result->negfuncid = InvalidOid;
result->useOr = useOr; /* inputcollid will be set by parse_collate.c */
result->args = args;
result->location = location;
/* *make_oper_cache_key *Fillthelookupkeystructgivenoperatornameandargtypes. * *Returnstrueifsuccessful,falseifthesearch_pathoverflowed *(hencenocachingispossible). * *pstate/locationareusedonlytoreporttheerrorposition;passNULL/-1 *ifnotavailable.
*/ staticbool
make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname,
Oid ltypeId, Oid rtypeId, int location)
{ 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)
{
ParseCallbackState pcbstate;
/* search only in exact schema given */
setup_parser_errposition_callback(&pcbstate, pstate, location);
key->search_path[0] = LookupExplicitNamespace(schemaname, false);
cancel_parser_errposition_callback(&pcbstate);
} else
{ /* get the active search path */ if (fetch_search_path_array(key->search_path,
MAX_CACHED_PATH_LEN) > MAX_CACHED_PATH_LEN) returnfalse; /* oops, didn't fit */
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.27Bemerkung:
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.