mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Some early work on error message editing. Operator-not-found and
function-not-found messages now distinguish the cases no-match and ambiguous-match, and they follow the style guidelines too.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
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),
|
||||
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));
|
||||
StringInfoData argbuf;
|
||||
|
||||
if (!typeidIsValid(arg2))
|
||||
elog(ERROR, "Right hand side of operator %s has an unknown type"
|
||||
"\n\tProbably a bad attribute name",
|
||||
NameListToString(op));
|
||||
initStringInfo(&argbuf);
|
||||
|
||||
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));
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user