📄 parse_oper.c
字号:
Operatoroper(List *opname, Oid ltypeId, Oid rtypeId, bool noError){ FuncCandidateList clist; Oid inputOids[2]; Oid operOid; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Get binary operators of given name */ clist = OpernameGetCandidates(opname, 'b'); /* No operators found? Then fail... */ if (clist != NULL) { /* * Check for an "exact" match. */ operOid = binary_oper_exact(ltypeId, rtypeId, clist); if (!OidIsValid(operOid)) { /* * Otherwise, search for the most suitable candidate. */ /* * Unspecified type for one of the arguments? then use the other * (XXX this is probably dead code?) */ 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 = SearchSysCache(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); } if (!HeapTupleIsValid(tup) && !noError) op_error(opname, 'b', ltypeId, rtypeId, fdresult); return (Operator) tup;}/* compatible_oper() * given an opname and input datatypes, find a compatible binary operator * * This is tighter than oper() because it will not return an operator that * requires coercion of the input datatypes (but binary-compatible operators * are accepted). Otherwise, the semantics are the same. */Operatorcompatible_oper(List *op, Oid arg1, Oid arg2, bool noError){ Operator optup; Form_pg_operator opform; /* oper() will find the best available match */ optup = oper(op, arg1, arg2, noError); 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)))); return (Operator) NULL;}/* compatible_oper_opid() -- get OID of a binary operator * * This is a convenience routine that extracts only the operator OID * from the result of compatible_oper(). InvalidOid is returned if the * lookup fails and noError is true. */Oidcompatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError){ Operator optup; Oid result; optup = compatible_oper(op, arg1, arg2, noError); if (optup != NULL) { result = oprid(optup); ReleaseSysCache(optup); return result; } return InvalidOid;}/* right_oper() -- search for a unary right operator (postfix operator) * Given operator name and type of arg, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatype. Do not use this if * you need an exact- or binary-compatible match. * * If no matching operator found, return NULL if noError is true, * raise an error if it is false. * * NOTE: on success, the returned object is a syscache entry. The caller * must ReleaseSysCache() the entry when done with it. */Operatorright_oper(List *op, Oid arg, bool noError){ FuncCandidateList clist; Oid operOid = InvalidOid; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Find candidates */ clist = OpernameGetCandidates(op, 'r'); if (clist != NULL) { /* * First, quickly check to see if there is an exactly matching * operator (there can be only one such entry in the list). */ FuncCandidateList clisti; for (clisti = clist; clisti != NULL; clisti = clisti->next) { if (arg == clisti->args[0]) { operOid = clisti->oid; break; } } if (!OidIsValid(operOid)) { /* * 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 = SearchSysCache(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); } if (!HeapTupleIsValid(tup) && !noError) op_error(op, 'r', arg, InvalidOid, fdresult); return (Operator) tup;}/* left_oper() -- search for a unary left operator (prefix operator) * Given operator name and type of arg, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatype. Do not use this if * you need an exact- or binary-compatible match. * * If no matching operator found, return NULL if noError is true, * raise an error if it is false. * * NOTE: on success, the returned object is a syscache entry. The caller * must ReleaseSysCache() the entry when done with it. */Operatorleft_oper(List *op, Oid arg, bool noError){ FuncCandidateList clist; Oid operOid = InvalidOid; FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Find candidates */ clist = OpernameGetCandidates(op, 'l'); if (clist != NULL) { /* * First, quickly check to see if there is an exactly matching * operator (there can be only one such entry in the list). * * 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]; if (arg == clisti->args[0]) { operOid = clisti->oid; break; } } if (!OidIsValid(operOid)) { /* * 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 = SearchSysCache(OPEROID, ObjectIdGetDatum(operOid), 0, 0, 0); } if (!HeapTupleIsValid(tup) && !noError) op_error(op, 'l', InvalidOid, arg, fdresult); return (Operator) tup;}/* * op_signature_string * Build a string representing an operator name, including arg type(s). * The result is something like "integer + integer". * * This is typically used in the construction of operator-not-found error * messages. */static const char *op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2){ 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 */}/* * op_error - utility routine to complain about an unresolvable operator */static voidop_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult){ 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 may need to add explicit type casts."))); 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 may need to add explicit type casts.")));}/* * make_op() * Operator expression construction. * * Transform operator expression ensuring type compatibility. * This is where some type conversion happens. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Expr *make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree){ Oid ltypeId, rtypeId; Operator tup; Expr *result; /* Select the operator */ if (rtree == NULL) { /* right operator */ ltypeId = exprType(ltree); rtypeId = InvalidOid; tup = right_oper(opname, ltypeId, false); } else if (ltree == NULL) { /* left operator */ rtypeId = exprType(rtree); ltypeId = InvalidOid; tup = left_oper(opname, rtypeId, false); } else { /* otherwise, binary operator */ ltypeId = exprType(ltree); rtypeId = exprType(rtree); tup = oper(opname, ltypeId, rtypeId, false); } /* Do typecasting and build the expression tree */ result = make_op_expr(pstate, tup, ltree, rtree, ltypeId, rtypeId); ReleaseSysCache(tup); return result;}/* * make_scalar_array_op() * Build expression tree for "scalar op ANY/ALL (array)" construct. */Expr *make_scalar_array_op(ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree){ 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_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"))); } /* Now resolve the operator */ tup = oper(opname, ltypeId, rtypeId, false); opform = (Form_pg_operator) GETSTRUCT(tup); 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 ANYARRAY and ANYELEMENT 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); /* * 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"))); 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"))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. */ 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])))); 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 = InvalidOid; result->useOr = useOr; result->args = args; ReleaseSysCache(tup); return (Expr *) result;}/* * make_op_expr() * Build operator expression using an already-looked-up operator. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Expr *make_op_expr(ParseState *pstate, Operator op, Node *ltree, Node *rtree, Oid ltypeId, Oid rtypeId){ Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op); Oid actual_arg_types[2]; Oid declared_arg_types[2]; int nargs; List *args; Oid rettype; OpExpr *result; 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 ANYARRAY and ANYELEMENT 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); /* 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(op); result->opfuncid = InvalidOid; result->opresulttype = rettype; result->opretset = get_func_retset(opform->oprcode); result->args = args; return (Expr *) result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -