aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_oper.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-03-14 22:48:25 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-03-14 22:48:25 +0000
commit20ab467d76d78271006818d2baf4c9c8658d1f38 (patch)
tree7a536111b5cc4e494ac75558aad5655dfc8ab964 /src/backend/parser/parse_oper.c
parent48fb696753e267447f99914c7968d0b4ffb5c5dc (diff)
downloadpostgresql-20ab467d76d78271006818d2baf4c9c8658d1f38.tar.gz
postgresql-20ab467d76d78271006818d2baf4c9c8658d1f38.zip
Improve parser so that we can show an error cursor position for errors
during parse analysis, not only errors detected in the flex/bison stages. This is per my earlier proposal. This commit includes all the basic infrastructure, but locations are only tracked and reported for errors involving column references, function calls, and operators. More could be done later but this seems like a good set to start with. I've also moved the ReportSyntaxErrorPosition logic out of psql and into libpq, which should make it available to more people --- even within psql this is an improvement because warnings weren't handled by ReportSyntaxErrorPosition.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r--src/backend/parser/parse_oper.c111
1 files changed, 60 insertions, 51 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2bd65b2e126..e483372e852 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.85 2006/03/05 15:58:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.86 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,8 +37,9 @@ static FuncDetailCode oper_select_candidate(int nargs,
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);
+static void op_error(ParseState *pstate, List *op, char oprkind,
+ Oid arg1, Oid arg2,
+ FuncDetailCode fdresult, int location);
static Expr *make_op_expr(ParseState *pstate, Operator op,
Node *ltree, Node *rtree,
Oid ltypeId, Oid rtypeId);
@@ -56,10 +57,12 @@ static Expr *make_op_expr(ParseState *pstate, Operator op,
* namespace search path.
*
* If the operator is not found, we return InvalidOid if noError is true,
- * else raise an error.
+ * else raise an error. pstate and location are used only to report the
+ * error position; pass NULL/-1 if not available.
*/
Oid
-LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
+LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
+ bool noError, int location)
{
FuncCandidateList clist;
char oprkind;
@@ -86,7 +89,8 @@ LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s",
op_signature_string(opername, oprkind,
- oprleft, oprright))));
+ oprleft, oprright)),
+ parser_errposition(pstate, location)));
return InvalidOid;
}
@@ -99,8 +103,9 @@ LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
* Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op.
*/
Oid
-LookupOperNameTypeNames(List *opername, TypeName *oprleft,
- TypeName *oprright, bool noError)
+LookupOperNameTypeNames(ParseState *pstate, List *opername,
+ TypeName *oprleft, TypeName *oprright,
+ bool noError, int location)
{
Oid leftoid,
rightoid;
@@ -108,27 +113,15 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft,
if (oprleft == NULL)
leftoid = InvalidOid;
else
- {
- leftoid = LookupTypeName(oprleft);
- if (!OidIsValid(leftoid))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("type %s does not exist",
- TypeNameToString(oprleft))));
- }
+ leftoid = typenameTypeId(pstate, oprleft);
+
if (oprright == NULL)
rightoid = InvalidOid;
else
- {
- rightoid = LookupTypeName(oprright);
- if (!OidIsValid(rightoid))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("type %s does not exist",
- TypeNameToString(oprright))));
- }
+ rightoid = typenameTypeId(pstate, oprright);
- return LookupOperName(opername, leftoid, rightoid, noError);
+ return LookupOperName(pstate, opername, leftoid, rightoid,
+ noError, location);
}
/*
@@ -500,13 +493,15 @@ oper_select_candidate(int nargs,
* you need an exact- or binary-compatible match; see compatible_oper.
*
* If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.
+ * raise an error if it is false. pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
Operator
-oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
+oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
+ bool noError, int location)
{
FuncCandidateList clist;
Oid inputOids[2];
@@ -549,7 +544,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
}
if (!HeapTupleIsValid(tup) && !noError)
- op_error(opname, 'b', ltypeId, rtypeId, fdresult);
+ op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);
return (Operator) tup;
}
@@ -562,13 +557,14 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
* are accepted). Otherwise, the semantics are the same.
*/
Operator
-compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
+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(op, arg1, arg2, noError);
+ optup = oper(pstate, op, arg1, arg2, noError, location);
if (optup == (Operator) NULL)
return (Operator) NULL; /* must be noError case */
@@ -585,7 +581,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator requires run-time type coercion: %s",
- op_signature_string(op, 'b', arg1, arg2))));
+ op_signature_string(op, 'b', arg1, arg2)),
+ parser_errposition(pstate, location)));
return (Operator) NULL;
}
@@ -602,7 +599,7 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Operator optup;
Oid result;
- optup = compatible_oper(op, arg1, arg2, noError);
+ optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
if (optup != NULL)
{
result = oprid(optup);
@@ -621,13 +618,14 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
* 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.
+ * raise an error if it is false. pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
Operator
-right_oper(List *op, Oid arg, bool noError)
+right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
FuncCandidateList clist;
Oid operOid = InvalidOid;
@@ -669,7 +667,7 @@ right_oper(List *op, Oid arg, bool noError)
}
if (!HeapTupleIsValid(tup) && !noError)
- op_error(op, 'r', arg, InvalidOid, fdresult);
+ op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
return (Operator) tup;
}
@@ -683,13 +681,14 @@ right_oper(List *op, Oid arg, bool noError)
* 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.
+ * raise an error if it is false. pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
Operator
-left_oper(List *op, Oid arg, bool noError)
+left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
FuncCandidateList clist;
Oid operOid = InvalidOid;
@@ -736,7 +735,7 @@ left_oper(List *op, Oid arg, bool noError)
}
if (!HeapTupleIsValid(tup) && !noError)
- op_error(op, 'l', InvalidOid, arg, fdresult);
+ op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);
return (Operator) tup;
}
@@ -771,7 +770,9 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
* op_error - utility routine to complain about an unresolvable operator
*/
static void
-op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
+op_error(ParseState *pstate, List *op, char oprkind,
+ Oid arg1, Oid arg2,
+ FuncDetailCode fdresult, int location)
{
if (fdresult == FUNCDETAIL_MULTIPLE)
ereport(ERROR,
@@ -779,14 +780,16 @@ op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
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.")));
+ "You may 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, oprkind, arg1, arg2)),
errhint("No operator matches the given name and argument type(s). "
- "You may need to add explicit type casts.")));
+ "You may need to add explicit type casts."),
+ parser_errposition(pstate, location)));
}
/*
@@ -800,7 +803,8 @@ op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
* processing is wanted.
*/
Expr *
-make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
+make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
+ int location)
{
Oid ltypeId,
rtypeId;
@@ -813,21 +817,21 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
/* right operator */
ltypeId = exprType(ltree);
rtypeId = InvalidOid;
- tup = right_oper(opname, ltypeId, false);
+ tup = right_oper(pstate, opname, ltypeId, false, location);
}
else if (ltree == NULL)
{
/* left operator */
rtypeId = exprType(rtree);
ltypeId = InvalidOid;
- tup = left_oper(opname, rtypeId, false);
+ tup = left_oper(pstate, opname, rtypeId, false, location);
}
else
{
/* otherwise, binary operator */
ltypeId = exprType(ltree);
rtypeId = exprType(rtree);
- tup = oper(opname, ltypeId, rtypeId, false);
+ tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
}
/* Do typecasting and build the expression tree */
@@ -845,7 +849,8 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
Expr *
make_scalar_array_op(ParseState *pstate, List *opname,
bool useOr,
- Node *ltree, Node *rtree)
+ Node *ltree, Node *rtree,
+ int location)
{
Oid ltypeId,
rtypeId,
@@ -875,11 +880,12 @@ make_scalar_array_op(ParseState *pstate, List *opname,
if (!OidIsValid(rtypeId))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("op ANY/ALL (array) requires array on right side")));
+ errmsg("op ANY/ALL (array) requires array on right side"),
+ parser_errposition(pstate, location)));
}
/* Now resolve the operator */
- tup = oper(opname, ltypeId, rtypeId, false);
+ tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
opform = (Form_pg_operator) GETSTRUCT(tup);
args = list_make2(ltree, rtree);
@@ -904,11 +910,13 @@ make_scalar_array_op(ParseState *pstate, List *opname,
if (rettype != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("op ANY/ALL (array) requires operator to yield boolean")));
+ 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")));
+ errmsg("op ANY/ALL (array) requires operator not to return a set"),
+ parser_errposition(pstate, location)));
/*
* Now switch back to the array type on the right, arranging for any
@@ -919,7 +927,8 @@ make_scalar_array_op(ParseState *pstate, List *opname,
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find array type for data type %s",
- format_type_be(declared_arg_types[1]))));
+ format_type_be(declared_arg_types[1])),
+ parser_errposition(pstate, location)));
actual_arg_types[1] = atypeId;
declared_arg_types[1] = res_atypeId;