diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_func.c | 119 | ||||
-rw-r--r-- | src/backend/parser/parse_oper.c | 202 |
2 files changed, 166 insertions, 155 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 806138a25a5..cb2da292a06 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.152 2003/06/25 21:30:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.153 2003/07/04 02:51:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -294,10 +294,23 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, /* * Else generate a detailed complaint for a function */ - func_error(NULL, funcname, nargs, actual_arg_types, - "Unable to identify a function that satisfies the " - "given argument types" - "\n\tYou may need to add explicit typecasts"); + if (fdresult == FUNCDETAIL_MULTIPLE) + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("function %s is not unique", + func_signature_string(funcname, nargs, + actual_arg_types)), + errhint("Unable to choose a best candidate function. " + "You may need to add explicit typecasts."))); + + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(funcname, nargs, + actual_arg_types)), + errhint("No function matches the given name and argument types. " + "You may need to add explicit typecasts."))); } /* @@ -874,11 +887,11 @@ func_get_detail(List *funcname, /* * If we were able to choose a best candidate, we're - * done. Otherwise, ambiguous function call, so fail - * by exiting loop with best_candidate still NULL. - * Either way, we're outta here. + * done. Otherwise, ambiguous function call. */ - break; + if (best_candidate) + break; + return FUNCDETAIL_MULTIPLE; } /* @@ -908,7 +921,8 @@ func_get_detail(List *funcname, ObjectIdGetDatum(best_candidate->oid), 0, 0, 0); if (!HeapTupleIsValid(ftup)) /* should not happen */ - elog(ERROR, "function %u not found", best_candidate->oid); + elog(ERROR, "cache lookup of function %u failed", + best_candidate->oid); pform = (Form_pg_proc) GETSTRUCT(ftup); *rettype = pform->prorettype; *retset = pform->proretset; @@ -918,7 +932,7 @@ func_get_detail(List *funcname, } return FUNCDETAIL_NOTFOUND; -} /* func_get_detail() */ +} /* * argtype_inherit() -- Construct an argtype vector reflecting the @@ -1324,19 +1338,23 @@ unknown_attribute(const char *schemaname, const char *relname, } /* - * Error message when function lookup fails that gives details of the - * argument types + * func_signature_string + * Build a string representing a function name, including arg types. + * The result is something like "foo(integer)". + * + * This is typically used in the construction of function-not-found error + * messages. */ -void -func_error(const char *caller, List *funcname, - int nargs, const Oid *argtypes, - const char *msg) +const char * +func_signature_string(List *funcname, int nargs, const Oid *argtypes) { StringInfoData argbuf; int i; initStringInfo(&argbuf); + appendStringInfo(&argbuf, "%s(", NameListToString(funcname)); + for (i = 0; i < nargs; i++) { if (i) @@ -1344,18 +1362,9 @@ func_error(const char *caller, List *funcname, appendStringInfoString(&argbuf, format_type_be(argtypes[i])); } - if (caller == NULL) - { - elog(ERROR, "Function %s(%s) does not exist%s%s", - NameListToString(funcname), argbuf.data, - ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); - } - else - { - elog(ERROR, "%s: function %s(%s) does not exist%s%s", - caller, NameListToString(funcname), argbuf.data, - ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); - } + appendStringInfoChar(&argbuf, ')'); + + return argbuf.data; /* return palloc'd string buffer */ } /* @@ -1367,23 +1376,24 @@ func_error(const char *caller, List *funcname, * all types. */ Oid -find_aggregate_func(const char *caller, List *aggname, Oid basetype) +find_aggregate_func(List *aggname, Oid basetype, bool noError) { Oid oid; HeapTuple ftup; Form_pg_proc pform; - oid = LookupFuncName(aggname, 1, &basetype); + oid = LookupFuncName(aggname, 1, &basetype, true); if (!OidIsValid(oid)) { + if (noError) + return InvalidOid; if (basetype == ANYOID) - elog(ERROR, "%s: aggregate %s(*) does not exist", - caller, NameListToString(aggname)); + elog(ERROR, "aggregate %s(*) does not exist", + NameListToString(aggname)); else - elog(ERROR, "%s: aggregate %s(%s) does not exist", - caller, NameListToString(aggname), - format_type_be(basetype)); + elog(ERROR, "aggregate %s(%s) does not exist", + NameListToString(aggname), format_type_be(basetype)); } /* Make sure it's an aggregate */ @@ -1396,13 +1406,12 @@ find_aggregate_func(const char *caller, List *aggname, Oid basetype) if (!pform->proisagg) { - if (basetype == ANYOID) - elog(ERROR, "%s: function %s(*) is not an aggregate", - caller, NameListToString(aggname)); - else - elog(ERROR, "%s: function %s(%s) is not an aggregate", - caller, NameListToString(aggname), - format_type_be(basetype)); + ReleaseSysCache(ftup); + if (noError) + return InvalidOid; + /* we do not use the (*) notation for functions... */ + elog(ERROR, "function %s(%s) is not an aggregate", + NameListToString(aggname), format_type_be(basetype)); } ReleaseSysCache(ftup); @@ -1413,13 +1422,16 @@ find_aggregate_func(const char *caller, List *aggname, Oid basetype) /* * LookupFuncName * Given a possibly-qualified function name and a set of argument types, - * look up the function. Returns InvalidOid if no such function. + * look up the function. * * If the function name is not schema-qualified, it is sought in the current * namespace search path. + * + * If the function is not found, we return InvalidOid if noError is true, + * else raise an error. */ Oid -LookupFuncName(List *funcname, int nargs, const Oid *argtypes) +LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) { FuncCandidateList clist; @@ -1432,19 +1444,21 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes) clist = clist->next; } + if (!noError) + elog(ERROR, "function %s does not exist", + func_signature_string(funcname, nargs, argtypes)); + return InvalidOid; } /* * LookupFuncNameTypeNames * Like LookupFuncName, but the argument types are specified by a - * list of TypeName nodes. Also, if we fail to find the function - * and caller is not NULL, then an error is reported via func_error. + * list of TypeName nodes. */ Oid -LookupFuncNameTypeNames(List *funcname, List *argtypes, const char *caller) +LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError) { - Oid funcoid; Oid argoids[FUNC_MAX_ARGS]; int argcount; int i; @@ -1468,10 +1482,5 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, const char *caller) argtypes = lnext(argtypes); } - funcoid = LookupFuncName(funcname, argcount, argoids); - - if (!OidIsValid(funcoid) && caller != NULL) - func_error(caller, funcname, argcount, argoids, NULL); - - return funcoid; + return LookupFuncName(funcname, argcount, argoids, noError); } diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 72327243310..99b5a3078ca 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.68 2003/06/29 00:33:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.69 2003/07/04 02:51:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "postgres.h" #include "catalog/pg_operator.h" +#include "lib/stringinfo.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" #include "parser/parse_func.h" @@ -29,25 +30,32 @@ static Oid binary_oper_exact(Oid arg1, Oid arg2, FuncCandidateList candidates); -static Oid oper_select_candidate(int nargs, Oid *input_typeids, - FuncCandidateList candidates); -static void op_error(List *op, Oid arg1, Oid arg2); -static void unary_op_error(List *op, Oid arg, bool is_left_op); +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(List *op, char oprkind, Oid arg1, Oid arg2, + FuncDetailCode fdresult); /* * LookupOperName * Given a possibly-qualified operator name and exact input datatypes, - * look up the operator. Returns InvalidOid if no such operator. + * look up the operator. * * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for * a postfix op. * * If the operator name is not schema-qualified, it is sought in the current * namespace search path. + * + * If the operator is not found, we return InvalidOid if noError is true, + * else raise an error. */ Oid -LookupOperName(List *opername, Oid oprleft, Oid oprright) +LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError) { FuncCandidateList clist; char oprkind; @@ -68,22 +76,28 @@ LookupOperName(List *opername, Oid oprleft, Oid oprright) clist = clist->next; } + /* we don't use op_error here because only an exact match is wanted */ + if (!noError) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator does not exist: %s", + op_signature_string(opername, oprkind, + oprleft, oprright)))); + return InvalidOid; } /* * LookupOperNameTypeNames * Like LookupOperName, but the argument types are specified by - * TypeName nodes. Also, if we fail to find the operator - * and caller is not NULL, then an error is reported. + * TypeName nodes. * * Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op. */ Oid LookupOperNameTypeNames(List *opername, TypeName *oprleft, - TypeName *oprright, const char *caller) + TypeName *oprright, bool noError) { - Oid operoid; Oid leftoid, rightoid; @@ -93,7 +107,7 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft, { leftoid = LookupTypeName(oprleft); if (!OidIsValid(leftoid)) - elog(ERROR, "Type \"%s\" does not exist", + elog(ERROR, "type %s does not exist", TypeNameToString(oprleft)); } if (oprright == NULL) @@ -102,30 +116,11 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft, { rightoid = LookupTypeName(oprright); if (!OidIsValid(rightoid)) - elog(ERROR, "Type \"%s\" does not exist", - TypeNameToString(oprright)); - } - - operoid = LookupOperName(opername, leftoid, rightoid); - - if (!OidIsValid(operoid) && caller != NULL) - { - if (oprleft == NULL) - elog(ERROR, "%s: Prefix operator '%s' for type '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprright)); - else if (oprright == NULL) - elog(ERROR, "%s: Postfix operator '%s' for type '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprleft)); - else - elog(ERROR, "%s: Operator '%s' for types '%s' and '%s' does not exist", - caller, NameListToString(opername), - TypeNameToString(oprleft), + elog(ERROR, "type %s does not exist", TypeNameToString(oprright)); } - return operoid; + return LookupOperName(opername, leftoid, rightoid, noError); } /* @@ -183,7 +178,7 @@ equality_oper(Oid argtype, bool noError) } } if (!noError) - elog(ERROR, "Unable to identify an equality operator for type %s", + elog(ERROR, "unable to identify an equality operator for type %s", format_type_be(argtype)); return NULL; } @@ -244,7 +239,7 @@ ordering_oper(Oid argtype, bool noError) } } if (!noError) - elog(ERROR, "Unable to identify an ordering operator for type %s" + elog(ERROR, "unable to identify an ordering operator for type %s" "\n\tUse an explicit ordering operator or modify the query", format_type_be(argtype)); return NULL; @@ -347,17 +342,18 @@ binary_oper_exact(Oid arg1, Oid arg2, * Given the input argtype array and one or more candidates * for the operator, attempt to resolve the conflict. * - * Returns the OID of the selected operator if the conflict can be resolved, - * otherwise returns InvalidOid. + * Returns FUNCDETAIL_NOTFOUND, FUNCDETAIL_MULTIPLE, or FUNCDETAIL_NORMAL. + * In the success case the Oid of the best candidate is stored in *operOid. * * Note that the caller has already determined that there is no candidate * exactly matching the input argtype(s). Incompatible candidates are not yet * pruned away, however. */ -static Oid +static FuncDetailCode oper_select_candidate(int nargs, Oid *input_typeids, - FuncCandidateList candidates) + FuncCandidateList candidates, + Oid *operOid) /* output argument */ { int ncandidates; @@ -370,9 +366,15 @@ oper_select_candidate(int nargs, /* Done if no candidate or only one candidate survives */ if (ncandidates == 0) - return InvalidOid; + { + *operOid = InvalidOid; + return FUNCDETAIL_NOTFOUND; + } if (ncandidates == 1) - return candidates->oid; + { + *operOid = candidates->oid; + return FUNCDETAIL_NORMAL; + } /* * Use the same heuristics as for ambiguous functions to resolve @@ -381,10 +383,14 @@ oper_select_candidate(int nargs, candidates = func_select_candidate(nargs, input_typeids, candidates); if (candidates) - return candidates->oid; + { + *operOid = candidates->oid; + return FUNCDETAIL_NORMAL; + } - return InvalidOid; /* failed to select a best candidate */ -} /* oper_select_candidate() */ + *operOid = InvalidOid; + return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */ +} /* oper() -- search for a binary operator @@ -404,8 +410,9 @@ Operator oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) { FuncCandidateList clist; - Oid operOid; Oid inputOids[2]; + Oid operOid; + FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Get binary operators of given name */ @@ -434,7 +441,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) ltypeId = rtypeId; inputOids[0] = ltypeId; inputOids[1] = rtypeId; - operOid = oper_select_candidate(2, inputOids, clist); + fdresult = oper_select_candidate(2, inputOids, clist, &operOid); } if (OidIsValid(operOid)) tup = SearchSysCache(OPEROID, @@ -443,7 +450,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) } if (!HeapTupleIsValid(tup) && !noError) - op_error(opname, ltypeId, rtypeId); + op_error(opname, 'b', ltypeId, rtypeId, fdresult); return (Operator) tup; } @@ -476,7 +483,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError) ReleaseSysCache(optup); if (!noError) - op_error(op, arg1, arg2); + elog(ERROR, "operator requires run-time type coercion: %s", + op_signature_string(op, 'b', arg1, arg2)); return (Operator) NULL; } @@ -504,7 +512,7 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) } -/* right_oper() -- search for a unary right operator (operator on right) +/* 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 @@ -522,6 +530,7 @@ right_oper(List *op, Oid arg, bool noError) { FuncCandidateList clist; Oid operOid = InvalidOid; + FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Find candidates */ @@ -551,7 +560,7 @@ right_oper(List *op, Oid arg, bool noError) * candidate, otherwise we may falsely return a * non-type-compatible operator. */ - operOid = oper_select_candidate(1, &arg, clist); + fdresult = oper_select_candidate(1, &arg, clist, &operOid); } if (OidIsValid(operOid)) tup = SearchSysCache(OPEROID, @@ -560,13 +569,13 @@ right_oper(List *op, Oid arg, bool noError) } if (!HeapTupleIsValid(tup) && !noError) - unary_op_error(op, arg, FALSE); + op_error(op, 'r', arg, InvalidOid, fdresult); return (Operator) tup; } -/* left_oper() -- search for a unary left operator (operator on left) +/* 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 @@ -584,6 +593,7 @@ left_oper(List *op, Oid arg, bool noError) { FuncCandidateList clist; Oid operOid = InvalidOid; + FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND; HeapTuple tup = NULL; /* Find candidates */ @@ -618,7 +628,7 @@ left_oper(List *op, Oid arg, bool noError) * candidate, otherwise we may falsely return a * non-type-compatible operator. */ - operOid = oper_select_candidate(1, &arg, clist); + fdresult = oper_select_candidate(1, &arg, clist, &operOid); } if (OidIsValid(operOid)) tup = SearchSysCache(OPEROID, @@ -627,67 +637,59 @@ left_oper(List *op, Oid arg, bool noError) } if (!HeapTupleIsValid(tup) && !noError) - unary_op_error(op, arg, TRUE); + op_error(op, 'l', InvalidOid, arg, fdresult); return (Operator) tup; } - -/* op_error() - * Give a somewhat useful error message when the operator for two types - * is not found. +/* + * 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 void -op_error(List *op, Oid arg1, Oid arg2) +static const char * +op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2) { - if (!typeidIsValid(arg1)) - elog(ERROR, "Left hand side of operator '%s' has an unknown type" - "\n\tProbably a bad attribute name", - NameListToString(op)); - - if (!typeidIsValid(arg2)) - elog(ERROR, "Right hand side of operator %s has an unknown type" - "\n\tProbably a bad attribute name", - NameListToString(op)); - - elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'" - "\n\tYou will have to retype this query using an explicit cast", - NameListToString(op), - format_type_be(arg1), format_type_be(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 */ } -/* unary_op_error() - * Give a somewhat useful error message when the operator for one type - * is not found. +/* + * op_error - utility routine to complain about an unresolvable operator */ static void -unary_op_error(List *op, Oid arg, bool is_left_op) +op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult) { - if (!typeidIsValid(arg)) - { - if (is_left_op) - elog(ERROR, "operand of prefix operator '%s' has an unknown type" - "\n\t(probably an invalid column reference)", - NameListToString(op)); - else - elog(ERROR, "operand of postfix operator '%s' has an unknown type" - "\n\t(probably an invalid column reference)", - NameListToString(op)); - } + if (fdresult == FUNCDETAIL_MULTIPLE) + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("operator is not unique: %s", + op_signature_string(op, oprkind, arg1, arg2)), + errhint("Unable to choose a best candidate operator. " + "You may need to add explicit typecasts."))); else - { - if (is_left_op) - elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'" - "\n\tYou may need to add parentheses or an explicit cast", - NameListToString(op), format_type_be(arg)); - else - elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'" - "\n\tYou may need to add parentheses or an explicit cast", - NameListToString(op), format_type_be(arg)); - } + 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 typecasts."))); } - /* * make_op() * Operator expression construction. |