aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_oper.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-07-04 02:51:34 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-07-04 02:51:34 +0000
commit79fafdf49ca9b5adbe36fb21facddb4ef1d81241 (patch)
tree899cad919aba943e324e24b30dd7aa6183c0a901 /src/backend/parser/parse_oper.c
parentcdb8a844e62c50e87d5eef19ee29b50837b1c460 (diff)
downloadpostgresql-79fafdf49ca9b5adbe36fb21facddb4ef1d81241.tar.gz
postgresql-79fafdf49ca9b5adbe36fb21facddb4ef1d81241.zip
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.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r--src/backend/parser/parse_oper.c202
1 files changed, 102 insertions, 100 deletions
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.