diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-03-14 22:48:25 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-03-14 22:48:25 +0000 |
commit | 20ab467d76d78271006818d2baf4c9c8658d1f38 (patch) | |
tree | 7a536111b5cc4e494ac75558aad5655dfc8ab964 /src/backend/parser/parse_expr.c | |
parent | 48fb696753e267447f99914c7968d0b4ffb5c5dc (diff) | |
download | postgresql-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_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 162 |
1 files changed, 104 insertions, 58 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index ab4d681fdfd..cae682c9e77 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.190 2006/03/05 15:58:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.191 2006/03/14 22:48:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -57,18 +57,18 @@ static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, - char *relname); + char *relname, int location); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); static Node *typecast_expression(ParseState *pstate, Node *expr, TypeName *typename); static Node *make_row_comparison_op(ParseState *pstate, List *opname, - List *largs, List *rargs); + List *largs, List *rargs, int location); static Node *make_row_distinct_op(ParseState *pstate, List *opname, - RowExpr *lrow, RowExpr *rrow); + RowExpr *lrow, RowExpr *rrow, int location); static Expr *make_distinct_op(ParseState *pstate, List *opname, - Node *ltree, Node *rtree); + Node *ltree, Node *rtree, int location); /* @@ -308,7 +308,8 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection) result = ParseFuncOrColumn(pstate, list_make1(n), list_make1(result), - false, false, true); + false, false, true, + -1); } } /* process trailing subscripts, if any */ @@ -361,7 +362,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) char *name = strVal(linitial(cref->fields)); /* Try to identify as an unqualified column */ - node = colNameToVar(pstate, name, false); + node = colNameToVar(pstate, name, false, cref->location); if (node == NULL) { @@ -391,12 +392,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) */ if (refnameRangeTblEntry(pstate, NULL, name, &levels_up) != NULL) - node = transformWholeRowRef(pstate, NULL, name); + node = transformWholeRowRef(pstate, NULL, name, + cref->location); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", - name))); + name), + parser_errposition(pstate, cref->location))); } break; } @@ -408,12 +411,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) /* Whole-row reference? */ if (strcmp(name2, "*") == 0) { - node = transformWholeRowRef(pstate, NULL, name1); + node = transformWholeRowRef(pstate, NULL, name1, + cref->location); break; } /* Try to identify as a once-qualified column */ - node = qualifiedNameToVar(pstate, NULL, name1, name2, true); + node = qualifiedNameToVar(pstate, NULL, name1, name2, true, + cref->location); if (node == NULL) { /* @@ -421,11 +426,13 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) * it as a function call. Here, we will create an * implicit RTE for tables not already entered. */ - node = transformWholeRowRef(pstate, NULL, name1); + node = transformWholeRowRef(pstate, NULL, name1, + cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name2)), list_make1(node), - false, false, true); + false, false, true, + cref->location); } break; } @@ -438,20 +445,24 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) /* Whole-row reference? */ if (strcmp(name3, "*") == 0) { - node = transformWholeRowRef(pstate, name1, name2); + node = transformWholeRowRef(pstate, name1, name2, + cref->location); break; } /* Try to identify as a twice-qualified column */ - node = qualifiedNameToVar(pstate, name1, name2, name3, true); + node = qualifiedNameToVar(pstate, name1, name2, name3, true, + cref->location); if (node == NULL) { /* Try it as a function call */ - node = transformWholeRowRef(pstate, name1, name2); + node = transformWholeRowRef(pstate, name1, name2, + cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name3)), list_make1(node), - false, false, true); + false, false, true, + cref->location); } break; } @@ -469,25 +480,30 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cross-database references are not implemented: %s", - NameListToString(cref->fields)))); + NameListToString(cref->fields)), + parser_errposition(pstate, cref->location))); /* Whole-row reference? */ if (strcmp(name4, "*") == 0) { - node = transformWholeRowRef(pstate, name2, name3); + node = transformWholeRowRef(pstate, name2, name3, + cref->location); break; } /* Try to identify as a twice-qualified column */ - node = qualifiedNameToVar(pstate, name2, name3, name4, true); + node = qualifiedNameToVar(pstate, name2, name3, name4, true, + cref->location); if (node == NULL) { /* Try it as a function call */ - node = transformWholeRowRef(pstate, name2, name3); + node = transformWholeRowRef(pstate, name2, name3, + cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name4)), list_make1(node), - false, false, true); + false, false, true, + cref->location); } break; } @@ -495,7 +511,8 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", - NameListToString(cref->fields)))); + NameListToString(cref->fields)), + parser_errposition(pstate, cref->location))); node = NULL; /* keep compiler quiet */ break; } @@ -614,7 +631,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a) result = make_row_comparison_op(pstate, a->name, ((RowExpr *) lexpr)->args, - ((RowExpr *) rexpr)->args); + ((RowExpr *) rexpr)->args, + a->location); } else { @@ -625,7 +643,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a) result = (Node *) make_op(pstate, a->name, lexpr, - rexpr); + rexpr, + a->location); } return result; @@ -678,7 +697,8 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a) a->name, true, lexpr, - rexpr); + rexpr, + a->location); } static Node * @@ -691,7 +711,8 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a) a->name, false, lexpr, - rexpr); + rexpr, + a->location); } static Node * @@ -706,7 +727,8 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a) /* "row op row" */ return make_row_distinct_op(pstate, a->name, (RowExpr *) lexpr, - (RowExpr *) rexpr); + (RowExpr *) rexpr, + a->location); } else { @@ -714,7 +736,8 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a) return (Node *) make_distinct_op(pstate, a->name, lexpr, - rexpr); + rexpr, + a->location); } } @@ -728,11 +751,13 @@ transformAExprNullIf(ParseState *pstate, A_Expr *a) result = (Node *) make_op(pstate, a->name, lexpr, - rexpr); + rexpr, + a->location); if (((OpExpr *) result)->opresulttype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("NULLIF requires = operator to yield boolean"))); + errmsg("NULLIF requires = operator to yield boolean"), + parser_errposition(pstate, a->location))); /* * We rely on NullIfExpr and OpExpr being the same struct @@ -758,7 +783,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a) ltype = exprType(lexpr); foreach(telem, (List *) a->rexpr) { - rtype = LookupTypeName(lfirst(telem)); + rtype = typenameTypeId(pstate, lfirst(telem)); matched = (rtype == ltype); if (matched) break; @@ -864,7 +889,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a) a->name, useOr, lexpr, - (Node *) newa); + (Node *) newa, + a->location); } } @@ -883,17 +909,20 @@ transformAExprIn(ParseState *pstate, A_Expr *a) !IsA(rexpr, RowExpr)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("arguments of row IN must all be row expressions"))); + errmsg("arguments of row IN must all be row expressions"), + parser_errposition(pstate, a->location))); cmp = make_row_comparison_op(pstate, a->name, (List *) copyObject(((RowExpr *) lexpr)->args), - ((RowExpr *) rexpr)->args); + ((RowExpr *) rexpr)->args, + a->location); } else cmp = (Node *) make_op(pstate, a->name, copyObject(lexpr), - rexpr); + rexpr, + a->location); cmp = coerce_to_boolean(pstate, cmp, "IN"); if (result == NULL) @@ -931,7 +960,8 @@ transformFuncCall(ParseState *pstate, FuncCall *fn) targs, fn->agg_star, fn->agg_distinct, - false); + false, + fn->location); } static Node * @@ -994,7 +1024,8 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) /* shorthand form was specified, so expand... */ warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) placeholder, - warg); + warg, + -1); } neww->expr = (Expr *) transformExpr(pstate, warg); @@ -1173,7 +1204,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink) sublink->testexpr = make_row_comparison_op(pstate, sublink->operName, left_list, - right_list); + right_list, + -1); } return result; @@ -1394,7 +1426,8 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b) * a rowtype; either a named composite type, or RECORD. */ static Node * -transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname) +transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, + int location) { Node *result; RangeTblEntry *rte; @@ -1408,7 +1441,8 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname) &sublevels_up); if (rte == NULL) - rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname)); + rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname), + location); vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); @@ -1877,7 +1911,7 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) Oid inputType = exprType(expr); Oid targetType; - targetType = typenameTypeId(typename); + targetType = typenameTypeId(pstate, typename); if (inputType == InvalidOid) return expr; /* do nothing if NULL input */ @@ -1891,7 +1925,8 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", format_type_be(inputType), - format_type_be(targetType)))); + format_type_be(targetType)), + parser_errposition(pstate, typename->location))); return expr; } @@ -1910,7 +1945,7 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) */ static Node * make_row_comparison_op(ParseState *pstate, List *opname, - List *largs, List *rargs) + List *largs, List *rargs, int location) { RowCompareExpr *rcexpr; RowCompareType rctype; @@ -1929,7 +1964,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, if (nopers != list_length(rargs)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("unequal number of entries in row expressions"))); + errmsg("unequal number of entries in row expressions"), + parser_errposition(pstate, location))); /* * We can't compare zero-length rows because there is no principled @@ -1938,7 +1974,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, if (nopers == 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot compare rows of zero length"))); + errmsg("cannot compare rows of zero length"), + parser_errposition(pstate, location))); /* * Identify all the pairwise operators, using make_op so that @@ -1951,7 +1988,7 @@ make_row_comparison_op(ParseState *pstate, List *opname, Node *rarg = (Node *) lfirst(r); OpExpr *cmp; - cmp = (OpExpr *) make_op(pstate, opname, larg, rarg); + cmp = (OpExpr *) make_op(pstate, opname, larg, rarg, location); Assert(IsA(cmp, OpExpr)); /* @@ -1964,11 +2001,13 @@ make_row_comparison_op(ParseState *pstate, List *opname, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("row comparison operator must yield type boolean, " "not type %s", - format_type_be(cmp->opresulttype)))); + format_type_be(cmp->opresulttype)), + parser_errposition(pstate, location))); if (expression_returns_set((Node *) cmp)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("row comparison operator must not return a set"))); + errmsg("row comparison operator must not return a set"), + parser_errposition(pstate, location))); opexprs = lappend(opexprs, cmp); } @@ -2021,7 +2060,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine interpretation of row comparison operator %s", strVal(llast(opname))), - errhint("Row comparison operators must be associated with btree operator classes."))); + errhint("Row comparison operators must be associated with btree operator classes."), + parser_errposition(pstate, location))); rctype = 0; /* keep compiler quiet */ break; case BMS_SINGLETON: @@ -2069,7 +2109,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine interpretation of row comparison operator %s", strVal(llast(opname))), - errdetail("There are multiple equally-plausible candidates."))); + errdetail("There are multiple equally-plausible candidates."), + parser_errposition(pstate, location))); break; } } @@ -2120,7 +2161,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine interpretation of row comparison operator %s", strVal(llast(opname))), - errdetail("There are multiple equally-plausible candidates."))); + errdetail("There are multiple equally-plausible candidates."), + parser_errposition(pstate, location))); } /* @@ -2158,7 +2200,8 @@ make_row_comparison_op(ParseState *pstate, List *opname, */ static Node * make_row_distinct_op(ParseState *pstate, List *opname, - RowExpr *lrow, RowExpr *rrow) + RowExpr *lrow, RowExpr *rrow, + int location) { Node *result = NULL; List *largs = lrow->args; @@ -2169,7 +2212,8 @@ make_row_distinct_op(ParseState *pstate, List *opname, if (list_length(largs) != list_length(rargs)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("unequal number of entries in row expressions"))); + errmsg("unequal number of entries in row expressions"), + parser_errposition(pstate, location))); forboth(l, largs, r, rargs) { @@ -2177,7 +2221,7 @@ make_row_distinct_op(ParseState *pstate, List *opname, Node *rarg = (Node *) lfirst(r); Node *cmp; - cmp = (Node *) make_distinct_op(pstate, opname, larg, rarg); + cmp = (Node *) make_distinct_op(pstate, opname, larg, rarg, location); if (result == NULL) result = cmp; else @@ -2198,15 +2242,17 @@ make_row_distinct_op(ParseState *pstate, List *opname, * make the node for an IS DISTINCT FROM operator */ static Expr * -make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree) +make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, + int location) { Expr *result; - result = make_op(pstate, opname, ltree, rtree); + result = make_op(pstate, opname, ltree, rtree, location); if (((OpExpr *) result)->opresulttype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("IS DISTINCT FROM requires = operator to yield boolean"))); + errmsg("IS DISTINCT FROM requires = operator to yield boolean"), + parser_errposition(pstate, location))); /* * We rely on DistinctExpr and OpExpr being same struct |