summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c26
-rw-r--r--src/backend/parser/gram.y221
-rw-r--r--src/backend/parser/parse_clause.c14
-rw-r--r--src/backend/parser/parse_expr.c162
-rw-r--r--src/backend/parser/parse_func.c62
-rw-r--r--src/backend/parser/parse_node.c37
-rw-r--r--src/backend/parser/parse_oper.c111
-rw-r--r--src/backend/parser/parse_relation.c46
-rw-r--r--src/backend/parser/parse_target.c12
-rw-r--r--src/backend/parser/parse_type.c38
-rw-r--r--src/backend/parser/scan.l103
11 files changed, 527 insertions, 305 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 645a740be0..1c4dc36303 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.330 2006/03/05 15:58:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.331 2006/03/14 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -146,6 +146,9 @@ static bool check_parameter_resolution_walker(Node *node,
* parse_analyze
* Analyze a raw parse tree and transform it to Query form.
*
+ * If available, pass the source text from which the raw parse tree was
+ * generated; it's OK to pass NULL if this is not available.
+ *
* Optionally, information about $n parameter types can be supplied.
* References to $n indexes not defined by paramTypes[] are disallowed.
*
@@ -155,11 +158,13 @@ static bool check_parameter_resolution_walker(Node *node,
* a dummy CMD_UTILITY Query node.
*/
List *
-parse_analyze(Node *parseTree, Oid *paramTypes, int numParams)
+parse_analyze(Node *parseTree, const char *sourceText,
+ Oid *paramTypes, int numParams)
{
ParseState *pstate = make_parsestate(NULL);
List *result;
+ pstate->p_sourcetext = sourceText;
pstate->p_paramtypes = paramTypes;
pstate->p_numparams = numParams;
pstate->p_variableparams = false;
@@ -179,11 +184,13 @@ parse_analyze(Node *parseTree, Oid *paramTypes, int numParams)
* be modified or enlarged (via repalloc).
*/
List *
-parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams)
+parse_analyze_varparams(Node *parseTree, const char *sourceText,
+ Oid **paramTypes, int *numParams)
{
ParseState *pstate = make_parsestate(NULL);
List *result;
+ pstate->p_sourcetext = sourceText;
pstate->p_paramtypes = *paramTypes;
pstate->p_numparams = *numParams;
pstate->p_variableparams = true;
@@ -921,6 +928,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
funccallnode->args = list_make1(snamenode);
funccallnode->agg_star = false;
funccallnode->agg_distinct = false;
+ funccallnode->location = -1;
constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT;
@@ -1097,7 +1105,6 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
char *attributeName = NameStr(attribute->attname);
ColumnDef *def;
- TypeName *typename;
/*
* Ignore dropped columns in the parent.
@@ -1113,10 +1120,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
*/
def = makeNode(ColumnDef);
def->colname = pstrdup(attributeName);
- typename = makeNode(TypeName);
- typename->typeid = attribute->atttypid;
- typename->typmod = attribute->atttypmod;
- def->typename = typename;
+ def->typename = makeTypeNameFromOid(attribute->atttypid,
+ attribute->atttypmod);
def->inhcount = 0;
def->is_local = false;
def->is_not_null = attribute->attnotnull;
@@ -2608,7 +2613,7 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
foreach(l, stmt->argtypes)
{
TypeName *tn = lfirst(l);
- Oid toid = typenameTypeId(tn);
+ Oid toid = typenameTypeId(pstate, tn);
argtoids[i++] = toid;
}
@@ -2621,6 +2626,7 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
* from context.
*/
queries = parse_analyze_varparams((Node *) stmt->query,
+ pstate->p_sourcetext,
&argtoids, &nargs);
/*
@@ -3029,7 +3035,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
/*
* All we really need to do here is verify that the type is valid.
*/
- Type ctype = typenameType(column->typename);
+ Type ctype = typenameType(pstate, column->typename);
ReleaseSysCache(ctype);
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c86a6888f2..acaddb1365 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.534 2006/03/07 01:00:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.535 2006/03/14 22:48:20 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -61,6 +61,10 @@
#include "utils/numeric.h"
+/* Location tracking support --- simpler than bison's default */
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current = Rhs[1];
+
extern List *parsetree; /* final parse result is delivered here */
static bool QueryIsRule = FALSE;
@@ -72,7 +76,7 @@ static bool QueryIsRule = FALSE;
*/
/*#define __YYSCLASS*/
-static Node *makeColumnRef(char *relname, List *indirection);
+static Node *makeColumnRef(char *relname, List *indirection, int location);
static Node *makeTypeCast(Node *arg, TypeName *typename);
static Node *makeStringConst(char *str, TypeName *typename);
static Node *makeIntConst(int val);
@@ -81,7 +85,7 @@ static Node *makeAConst(Value *v);
static Node *makeRowNullTest(NullTestType test, RowExpr *row);
static DefElem *makeDefElem(char *name, Node *arg);
static A_Const *makeBoolAConst(bool state);
-static FuncCall *makeOverlaps(List *largs, List *rargs);
+static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
static void check_qualified_name(List *names);
static List *check_func_name(List *names);
static List *extractArgTypes(List *parameters);
@@ -90,12 +94,13 @@ static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, Node *lockingClause,
Node *limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
-static Node *doNegate(Node *n);
+static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
%}
%name-prefix="base_yy"
+%locations
%union
{
@@ -3705,6 +3710,7 @@ func_type: Typename { $$ = $1; }
$$->names = lcons(makeString($1), $2);
$$->pct_type = true;
$$->typmod = -1;
+ $$->location = @1;
}
| SETOF type_name attrs '%' TYPE_P
{
@@ -3713,6 +3719,7 @@ func_type: Typename { $$ = $1; }
$$->pct_type = true;
$$->typmod = -1;
$$->setof = TRUE;
+ $$->location = @2;
}
;
@@ -6053,6 +6060,7 @@ SimpleTypename:
$$ = makeNode(TypeName);
$$->names = lcons(makeString($1), $2);
$$->typmod = -1;
+ $$->location = @1;
}
;
@@ -6077,6 +6085,7 @@ GenericType:
type_name
{
$$ = makeTypeName($1);
+ $$->location = @1;
}
;
@@ -6540,6 +6549,7 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($5, $1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @2;
$$ = (Node *) n;
}
/*
@@ -6552,44 +6562,44 @@ a_expr: c_expr { $$ = $1; }
* also to b_expr and to the MathOp list above.
*/
| '+' a_expr %prec UMINUS
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' a_expr %prec UMINUS
- { $$ = doNegate($2); }
+ { $$ = doNegate($2, @1); }
| a_expr '+' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
| a_expr '-' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
| a_expr '*' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
| a_expr '/' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
| a_expr '%' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
| a_expr '^' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
| a_expr '<' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
| a_expr '>' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
| a_expr '=' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
| a_expr qual_Op a_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
| qual_Op a_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
| a_expr qual_Op %prec POSTFIXOP
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
| a_expr AND a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3); }
+ { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2); }
| a_expr OR a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2); }
| NOT a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1); }
| a_expr LIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
| a_expr LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -6597,10 +6607,11 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($3, $5);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n);
+ n->location = @4;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
}
| a_expr NOT LIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
| a_expr NOT LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -6608,10 +6619,11 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n);
+ n->location = @5;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
}
| a_expr ILIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
| a_expr ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -6619,10 +6631,11 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($3, $5);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n);
+ n->location = @4;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
}
| a_expr NOT ILIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
| a_expr NOT ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -6630,7 +6643,8 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n);
+ n->location = @5;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
}
| a_expr SIMILAR TO a_expr %prec SIMILAR
@@ -6642,7 +6656,8 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($4, (Node *) c);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n);
+ n->location = @2;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
}
| a_expr SIMILAR TO a_expr ESCAPE a_expr
{
@@ -6651,7 +6666,8 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n);
+ n->location = @5;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
}
| a_expr NOT SIMILAR TO a_expr %prec SIMILAR
{
@@ -6662,7 +6678,8 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($5, (Node *) c);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n);
+ n->location = @5;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
}
| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
{
@@ -6671,7 +6688,8 @@ a_expr: c_expr { $$ = $1; }
n->args = list_make2($5, $7);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n);
+ n->location = @6;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
}
/* NullTest clause
@@ -6733,7 +6751,7 @@ a_expr: c_expr { $$ = $1; }
}
| row OVERLAPS row
{
- $$ = (Node *)makeOverlaps($1, $3);
+ $$ = (Node *)makeOverlaps($1, $3, @2);
}
| a_expr IS TRUE_P
{
@@ -6779,54 +6797,63 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IS DISTINCT FROM a_expr %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
}
| a_expr IS NOT DISTINCT FROM a_expr %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
(Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
- "=", $1, $6));
+ "=", $1, $6, @2),
+ @2);
}
| a_expr IS OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
}
| a_expr IS NOT OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
}
| a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6));
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
+ @2);
}
| a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7));
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
+ @2);
}
| a_expr BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
(Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6)),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
+ @2),
(Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4)));
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2),
+ @2),
+ @2);
}
| a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
(Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7)),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
+ @2),
(Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5)));
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2),
+ @2),
+ @2);
}
| a_expr IN_P in_expr
{
@@ -6843,7 +6870,7 @@ a_expr: c_expr { $$ = $1; }
else
{
/* generate scalar IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
}
}
| a_expr NOT IN_P in_expr
@@ -6858,12 +6885,12 @@ a_expr: c_expr { $$ = $1; }
n->testexpr = $1;
n->operName = list_make1(makeString("="));
/* Stick a NOT on top */
- $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n);
+ $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
}
else
{
/* generate scalar NOT IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
}
}
| a_expr subquery_Op sub_type select_with_parens %prec Op
@@ -6878,9 +6905,9 @@ a_expr: c_expr { $$ = $1; }
| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
{
if ($3 == ANY_SUBLINK)
- $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5);
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
else
- $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5);
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
}
| UNIQUE select_with_parens
{
@@ -6913,49 +6940,49 @@ b_expr: c_expr
| b_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); }
| '+' b_expr %prec UMINUS
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
- { $$ = doNegate($2); }
+ { $$ = doNegate($2, @1); }
| b_expr '+' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
| b_expr '-' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
| b_expr '*' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
| b_expr '/' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
| b_expr '%' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
| b_expr '^' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
| b_expr '<' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
| b_expr '>' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
| b_expr '=' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
| b_expr qual_Op b_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
| qual_Op b_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
| b_expr qual_Op %prec POSTFIXOP
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
| b_expr IS DISTINCT FROM b_expr %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
}
| b_expr IS NOT DISTINCT FROM b_expr %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
- NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6));
+ NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2), @2);
}
| b_expr IS OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
}
| b_expr IS NOT OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
}
;
@@ -7052,6 +7079,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| func_name '(' expr_list ')'
@@ -7061,6 +7089,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| func_name '(' ALL expr_list ')'
@@ -7074,6 +7103,7 @@ func_expr: func_name '(' ')'
* "must be an aggregate", but there's no provision
* for that in FuncCall at the moment.
*/
+ n->location = @1;
$$ = (Node *)n;
}
| func_name '(' DISTINCT expr_list ')'
@@ -7083,6 +7113,7 @@ func_expr: func_name '(' ')'
n->args = $4;
n->agg_star = FALSE;
n->agg_distinct = TRUE;
+ n->location = @1;
$$ = (Node *)n;
}
| func_name '(' '*' ')'
@@ -7108,6 +7139,7 @@ func_expr: func_name '(' ')'
n->args = list_make1(star);
n->agg_star = TRUE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CURRENT_DATE
@@ -7196,6 +7228,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP '(' Iconst ')'
@@ -7331,6 +7364,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CURRENT_USER
@@ -7340,6 +7374,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| SESSION_USER
@@ -7349,6 +7384,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| USER
@@ -7358,6 +7394,7 @@ func_expr: func_name '(' ')'
n->args = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CAST '(' a_expr AS Typename ')'
@@ -7369,6 +7406,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| OVERLAY '(' overlay_list ')'
@@ -7383,6 +7421,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| POSITION '(' position_list ')'
@@ -7393,6 +7432,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| SUBSTRING '(' substr_list ')'
@@ -7405,6 +7445,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| TREAT '(' a_expr AS Typename ')'
@@ -7413,7 +7454,7 @@ func_expr: func_name '(' ')'
* which is defined to be a subtype of the original expression.
* In SQL99, this is intended for use with structured UDTs,
* but let's make this a generally useful form allowing stronger
- * coersions than are handled by implicit casting.
+ * coercions than are handled by implicit casting.
*/
FuncCall *n = makeNode(FuncCall);
/* Convert SystemTypeName() to SystemFuncName() even though
@@ -7421,6 +7462,9 @@ func_expr: func_name '(' ')'
*/
n->funcname = SystemFuncName(((Value *)llast($5->names))->val.str);
n->args = list_make1($3);
+ n->agg_star = FALSE;
+ n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| TRIM '(' BOTH trim_list ')'
@@ -7433,6 +7477,7 @@ func_expr: func_name '(' ')'
n->args = $4;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| TRIM '(' LEADING trim_list ')'
@@ -7442,6 +7487,7 @@ func_expr: func_name '(' ')'
n->args = $4;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| TRIM '(' TRAILING trim_list ')'
@@ -7451,6 +7497,7 @@ func_expr: func_name '(' ')'
n->args = $4;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| TRIM '(' trim_list ')'
@@ -7460,6 +7507,7 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CONVERT '(' a_expr USING any_name ')'
@@ -7474,6 +7522,7 @@ func_expr: func_name '(' ')'
n->args = list_make2($3, c);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| CONVERT '(' expr_list ')'
@@ -7483,11 +7532,12 @@ func_expr: func_name '(' ')'
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = @1;
$$ = (Node *)n;
}
| NULLIF '(' a_expr ',' a_expr ')'
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
}
| COALESCE '(' expr_list ')'
{
@@ -7797,11 +7847,11 @@ case_arg: a_expr { $$ = $1; }
*/
columnref: relation_name
{
- $$ = makeColumnRef($1, NIL);
+ $$ = makeColumnRef($1, NIL, @1);
}
| relation_name indirection
{
- $$ = makeColumnRef($1, $2);
+ $$ = makeColumnRef($1, $2, @1);
}
;
@@ -7875,6 +7925,7 @@ target_el: a_expr AS ColLabel
{
ColumnRef *n = makeNode(ColumnRef);
n->fields = list_make1(makeString("*"));
+ n->location = @1;
$$ = makeNode(ResTarget);
$$->name = NULL;
@@ -8585,7 +8636,7 @@ SpecialRuleRelation:
%%
static Node *
-makeColumnRef(char *relname, List *indirection)
+makeColumnRef(char *relname, List *indirection, int location)
{
/*
* Generate a ColumnRef node, with an A_Indirection node added if there
@@ -8597,6 +8648,7 @@ makeColumnRef(char *relname, List *indirection)
int nfields = 0;
ListCell *l;
+ c->location = location;
foreach(l, indirection)
{
if (IsA(lfirst(l), A_Indices))
@@ -8750,9 +8802,9 @@ makeRowNullTest(NullTestType test, RowExpr *row)
if (result == NULL)
result = (Node *) n;
else if (test == IS_NOT_NULL)
- result = (Node *) makeA_Expr(AEXPR_OR, NIL, result, (Node *)n);
+ result = (Node *) makeA_Expr(AEXPR_OR, NIL, result, (Node *)n, -1);
else
- result = (Node *) makeA_Expr(AEXPR_AND, NIL, result, (Node *)n);
+ result = (Node *) makeA_Expr(AEXPR_AND, NIL, result, (Node *)n, -1);
}
if (result == NULL)
@@ -8768,9 +8820,10 @@ makeRowNullTest(NullTestType test, RowExpr *row)
* Create and populate a FuncCall node to support the OVERLAPS operator.
*/
static FuncCall *
-makeOverlaps(List *largs, List *rargs)
+makeOverlaps(List *largs, List *rargs, int location)
{
FuncCall *n = makeNode(FuncCall);
+
n->funcname = SystemFuncName("overlaps");
if (list_length(largs) == 1)
largs = lappend(largs, largs);
@@ -8787,6 +8840,7 @@ makeOverlaps(List *largs, List *rargs)
n->args = list_concat(largs, rargs);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
+ n->location = location;
return n;
}
@@ -8944,6 +8998,7 @@ SystemTypeName(char *name)
n->names = list_make2(makeString("pg_catalog"), makeString(name));
n->typmod = -1;
+ n->location = -1;
return n;
}
@@ -8987,7 +9042,7 @@ exprIsNullConstant(Node *arg)
* until we know what the desired type is.
*/
static Node *
-doNegate(Node *n)
+doNegate(Node *n, int location)
{
if (IsA(n, A_Const))
{
@@ -9005,7 +9060,7 @@ doNegate(Node *n)
}
}
- return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n);
+ return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location);
}
static void
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index fdc2e41b3a..4384a4eaab 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.147 2006/03/05 21:34:34 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.148 2006/03/14 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -303,7 +303,9 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
Node *rvar = (Node *) lfirst(rvars);
A_Expr *e;
- e = makeSimpleA_Expr(AEXPR_OP, "=", copyObject(lvar), copyObject(rvar));
+ e = makeSimpleA_Expr(AEXPR_OP, "=",
+ copyObject(lvar), copyObject(rvar),
+ -1);
if (result == NULL)
result = (Node *) e;
@@ -311,7 +313,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
{
A_Expr *a;
- a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e);
+ a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e, -1);
result = (Node *) a;
}
}
@@ -1182,6 +1184,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
list_length(((ColumnRef *) node)->fields) == 1)
{
char *name = strVal(linitial(((ColumnRef *) node)->fields));
+ int location = ((ColumnRef *) node)->location;
if (clause == GROUP_CLAUSE)
{
@@ -1201,7 +1204,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
* breaks no cases that are legal per spec, and it seems a more
* self-consistent behavior.
*/
- if (colNameToVar(pstate, name, true) != NULL)
+ if (colNameToVar(pstate, name, true, location) != NULL)
name = NULL;
}
@@ -1225,7 +1228,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
* construct, eg ORDER BY
*/
errmsg("%s \"%s\" is ambiguous",
- clauseText[clause], name)));
+ clauseText[clause], name),
+ parser_errposition(pstate, location)));
}
else
target_result = tle;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index ab4d681fdf..cae682c9e7 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
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index d6b4307a61..35e826881f 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.184 2006/03/05 15:58:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.185 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,8 +34,9 @@
static Node *ParseComplexProjection(ParseState *pstate, char *funcname,
- Node *first_arg);
-static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
+ Node *first_arg, int location);
+static void unknown_attribute(ParseState *pstate, Node *relref, char *attname,
+ int location);
/*
@@ -59,7 +60,8 @@ static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
*/
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
- bool agg_star, bool agg_distinct, bool is_column)
+ bool agg_star, bool agg_distinct, bool is_column,
+ int location)
{
Oid rettype;
Oid funcid;
@@ -83,7 +85,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("cannot pass more than %d arguments to a function",
- FUNC_MAX_ARGS)));
+ FUNC_MAX_ARGS),
+ parser_errposition(pstate, location)));
/*
* Extract arg type info in preparation for function lookup.
@@ -131,7 +134,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
{
retval = ParseComplexProjection(pstate,
strVal(linitial(funcname)),
- first_arg);
+ first_arg,
+ location);
if (retval)
return retval;
@@ -174,12 +178,14 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s(*) specified, but %s is not an aggregate function",
NameListToString(funcname),
- NameListToString(funcname))));
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
if (agg_distinct)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("DISTINCT specified, but %s is not an aggregate function",
- NameListToString(funcname))));
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
}
else if (fdresult != FUNCDETAIL_AGGREGATE)
{
@@ -193,7 +199,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
{
Assert(nargs == 1);
Assert(list_length(funcname) == 1);
- unknown_attribute(pstate, first_arg, strVal(linitial(funcname)));
+ unknown_attribute(pstate, first_arg, strVal(linitial(funcname)),
+ location);
}
/*
@@ -206,7 +213,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
func_signature_string(funcname, nargs,
actual_arg_types)),
errhint("Could not choose a best candidate function. "
- "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),
@@ -214,7 +222,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
func_signature_string(funcname, nargs,
actual_arg_types)),
errhint("No function matches the given name and argument types. "
- "You may need to add explicit type casts.")));
+ "You may need to add explicit type casts."),
+ parser_errposition(pstate, location)));
}
/*
@@ -262,7 +271,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
if (retset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("aggregates may not return sets")));
+ errmsg("aggregates may not return sets"),
+ parser_errposition(pstate, location)));
}
return retval;
@@ -726,11 +736,9 @@ func_get_detail(List *funcname,
if (nargs == 1 && fargs != NIL)
{
Oid targetType;
- TypeName *tn = makeNode(TypeName);
- tn->names = funcname;
- tn->typmod = -1;
- targetType = LookupTypeName(tn);
+ targetType = LookupTypeName(NULL,
+ makeTypeNameFromNameList(funcname));
if (OidIsValid(targetType) &&
!ISCOMPLEX(targetType))
{
@@ -953,7 +961,8 @@ make_fn_arguments(ParseState *pstate,
* transformed expression tree. If not, return NULL.
*/
static Node *
-ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
+ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg,
+ int location)
{
TupleDesc tupdesc;
int i;
@@ -977,7 +986,7 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
((Var *) first_arg)->varno,
((Var *) first_arg)->varlevelsup);
/* Return a Var if funcname matches a column, else NULL */
- return scanRTEForColumn(pstate, rte, funcname);
+ return scanRTEForColumn(pstate, rte, funcname, location);
}
/*
@@ -1019,7 +1028,8 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
* helper routine for delivering "column does not exist" error message
*/
static void
-unknown_attribute(ParseState *pstate, Node *relref, char *attname)
+unknown_attribute(ParseState *pstate, Node *relref, char *attname,
+ int location)
{
RangeTblEntry *rte;
@@ -1033,7 +1043,8 @@ unknown_attribute(ParseState *pstate, Node *relref, char *attname)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %s.%s does not exist",
- rte->eref->aliasname, attname)));
+ rte->eref->aliasname, attname),
+ parser_errposition(pstate, location)));
}
else
{
@@ -1044,18 +1055,21 @@ unknown_attribute(ParseState *pstate, Node *relref, char *attname)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" not found in data type %s",
- attname, format_type_be(relTypeId))));
+ attname, format_type_be(relTypeId)),
+ parser_errposition(pstate, location)));
else if (relTypeId == RECORDOID)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("could not identify column \"%s\" in record data type",
- attname)));
+ attname),
+ parser_errposition(pstate, location)));
else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("column notation .%s applied to type %s, "
"which is not a composite type",
- attname, format_type_be(relTypeId))));
+ attname, format_type_be(relTypeId)),
+ parser_errposition(pstate, location)));
}
}
@@ -1219,7 +1233,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
{
TypeName *t = (TypeName *) lfirst(args_item);
- argoids[i] = LookupTypeName(t);
+ argoids[i] = LookupTypeName(NULL, t);
if (!OidIsValid(argoids[i]))
ereport(ERROR,
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 2ac869c9fc..23d73a13f2 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.91 2006/03/05 15:58:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.92 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_type.h"
+#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
@@ -44,13 +45,47 @@ make_parsestate(ParseState *parentParseState)
pstate->p_next_resno = 1;
if (parentParseState)
+ {
+ pstate->p_sourcetext = parentParseState->p_sourcetext;
pstate->p_variableparams = parentParseState->p_variableparams;
+ }
return pstate;
}
/*
+ * parser_errposition
+ * Report a parse-analysis-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call. The return value
+ * is a dummy (always 0, in fact).
+ *
+ * The locations stored in raw parsetrees are byte offsets into the source
+ * string. We have to convert them to 1-based character indexes for reporting
+ * to clients. (We do things this way to avoid unnecessary overhead in the
+ * normal non-error case: computing character indexes would be much more
+ * expensive than storing token offsets.)
+ */
+int
+parser_errposition(ParseState *pstate, int location)
+{
+ int pos;
+
+ /* No-op if location was not provided */
+ if (location < 0)
+ return 0;
+ /* Can't do anything if source text is not available */
+ if (pstate == NULL || pstate->p_sourcetext == NULL)
+ return 0;
+ /* Convert offset to character number */
+ pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1;
+ /* And pass it to the ereport mechanism */
+ return errposition(pos);
+}
+
+
+/*
* make_var
* Build a Var node for an attribute identified by RTE and attrno
*/
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2bd65b2e12..e483372e85 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;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index af8086a81a..d0f78b119c 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.119 2006/03/05 15:58:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.120 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,8 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
bool include_dropped,
List **colnames, List **colvars);
static int specialAttNum(const char *attname);
-static void warnAutoRange(ParseState *pstate, RangeVar *relation);
+static void warnAutoRange(ParseState *pstate, RangeVar *relation,
+ int location);
/*
@@ -329,7 +330,8 @@ GetRTEByRangeTablePosn(ParseState *pstate,
* FROM will be marked as requiring read access from the beginning.
*/
Node *
-scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
+scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
+ int location)
{
Node *result = NULL;
int attnum = 0;
@@ -357,7 +359,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
errmsg("column reference \"%s\" is ambiguous",
- colname)));
+ colname),
+ parser_errposition(pstate, location)));
result = (Node *) make_var(pstate, rte, attnum);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
@@ -404,7 +407,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
* If localonly is true, only names in the innermost query are considered.
*/
Node *
-colNameToVar(ParseState *pstate, char *colname, bool localonly)
+colNameToVar(ParseState *pstate, char *colname, bool localonly,
+ int location)
{
Node *result = NULL;
ParseState *orig_pstate = pstate;
@@ -419,7 +423,7 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
Node *newresult;
/* use orig_pstate here to get the right sublevels_up */
- newresult = scanRTEForColumn(orig_pstate, rte, colname);
+ newresult = scanRTEForColumn(orig_pstate, rte, colname, location);
if (newresult)
{
@@ -427,7 +431,8 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
errmsg("column reference \"%s\" is ambiguous",
- colname)));
+ colname),
+ parser_errposition(orig_pstate, location)));
result = newresult;
}
}
@@ -454,7 +459,8 @@ qualifiedNameToVar(ParseState *pstate,
char *schemaname,
char *refname,
char *colname,
- bool implicitRTEOK)
+ bool implicitRTEOK,
+ int location)
{
RangeTblEntry *rte;
int sublevels_up;
@@ -465,10 +471,11 @@ qualifiedNameToVar(ParseState *pstate,
{
if (!implicitRTEOK)
return NULL;
- rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname));
+ rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
+ location);
}
- return scanRTEForColumn(pstate, rte, colname);
+ return scanRTEForColumn(pstate, rte, colname, location);
}
/*
@@ -1043,12 +1050,12 @@ addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
* a conflicting name.
*/
RangeTblEntry *
-addImplicitRTE(ParseState *pstate, RangeVar *relation)
+addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
{
RangeTblEntry *rte;
/* issue warning or error as needed */
- warnAutoRange(pstate, relation);
+ warnAutoRange(pstate, relation, location);
/*
* Note that we set inFromCl true, so that the RTE will be listed
* explicitly if the parsetree is ever decompiled by ruleutils.c. This
@@ -1196,7 +1203,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
Var *varnode;
Oid atttypid;
- atttypid = typenameTypeId(colDef->typename);
+ atttypid = typenameTypeId(NULL, colDef->typename);
varnode = makeVar(rtindex,
attnum,
@@ -1543,7 +1550,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
{
ColumnDef *colDef = list_nth(rte->coldeflist, attnum - 1);
- *vartype = typenameTypeId(colDef->typename);
+ *vartype = typenameTypeId(NULL, colDef->typename);
*vartypmod = colDef->typename->typmod;
}
else
@@ -1802,7 +1809,7 @@ attnumTypeId(Relation rd, int attid)
* a warning.
*/
static void
-warnAutoRange(ParseState *pstate, RangeVar *relation)
+warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
{
RangeTblEntry *rte;
int sublevels_up;
@@ -1841,7 +1848,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias) :
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
- rte->eref->aliasname))));
+ rte->eref->aliasname)),
+ parser_errposition(pstate, location)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
@@ -1849,7 +1857,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
relation->relname) :
errmsg("missing FROM-clause entry for table \"%s\"",
- relation->relname))));
+ relation->relname)),
+ parser_errposition(pstate, location)));
}
else
{
@@ -1866,6 +1875,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
badAlias) :
(rte ?
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
- rte->eref->aliasname) : 0))));
+ rte->eref->aliasname) : 0)),
+ parser_errposition(pstate, location)));
}
}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 63ce087e71..300e02d90b 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.140 2006/03/05 15:58:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.141 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -718,7 +718,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cross-database references are not implemented: %s",
- NameListToString(fields))));
+ NameListToString(fields)),
+ parser_errposition(pstate, cref->location)));
schemaname = strVal(lsecond(fields));
relname = strVal(lthird(fields));
break;
@@ -727,7 +728,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper qualified name (too many dotted names): %s",
- NameListToString(fields))));
+ NameListToString(fields)),
+ parser_errposition(pstate, cref->location)));
schemaname = NULL; /* keep compiler quiet */
relname = NULL;
break;
@@ -736,8 +738,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
rte = refnameRangeTblEntry(pstate, schemaname, relname,
&sublevels_up);
if (rte == NULL)
- rte = addImplicitRTE(pstate, makeRangeVar(schemaname,
- relname));
+ rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
+ cref->location);
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 4114354057..e88e6c37c1 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.78 2006/03/05 15:58:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.79 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,9 +35,11 @@
*
* NB: even if the returned OID is not InvalidOid, the type might be
* just a shell. Caller should check typisdefined before using the type.
+ *
+ * pstate is only used for error location info, and may be NULL.
*/
Oid
-LookupTypeName(const TypeName *typename)
+LookupTypeName(ParseState *pstate, const TypeName *typename)
{
Oid restype;
@@ -60,7 +62,8 @@ LookupTypeName(const TypeName *typename)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper %%TYPE reference (too few dotted names): %s",
- NameListToString(typename->names))));
+ NameListToString(typename->names)),
+ parser_errposition(pstate, typename->location)));
break;
case 2:
rel->relname = strVal(linitial(typename->names));
@@ -81,7 +84,8 @@ LookupTypeName(const TypeName *typename)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper %%TYPE reference (too many dotted names): %s",
- NameListToString(typename->names))));
+ NameListToString(typename->names)),
+ parser_errposition(pstate, typename->location)));
break;
}
@@ -92,7 +96,8 @@ LookupTypeName(const TypeName *typename)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
- field, rel->relname)));
+ field, rel->relname),
+ parser_errposition(pstate, typename->location)));
restype = get_atttype(relid, attnum);
/* this construct should never have an array indicator */
@@ -190,21 +195,24 @@ TypeNameToString(const TypeName *typename)
* a suitable error message if the type cannot be found or is not defined.
*/
Oid
-typenameTypeId(const TypeName *typename)
+typenameTypeId(ParseState *pstate, const TypeName *typename)
{
Oid typoid;
- typoid = LookupTypeName(typename);
+ typoid = LookupTypeName(pstate, typename);
if (!OidIsValid(typoid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist",
- TypeNameToString(typename))));
+ TypeNameToString(typename)),
+ parser_errposition(pstate, typename->location)));
+
if (!get_typisdefined(typoid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" is only a shell",
- TypeNameToString(typename))));
+ TypeNameToString(typename)),
+ parser_errposition(pstate, typename->location)));
return typoid;
}
@@ -215,17 +223,18 @@ typenameTypeId(const TypeName *typename)
* NB: caller must ReleaseSysCache the type tuple when done with it.
*/
Type
-typenameType(const TypeName *typename)
+typenameType(ParseState *pstate, const TypeName *typename)
{
Oid typoid;
HeapTuple tup;
- typoid = LookupTypeName(typename);
+ typoid = LookupTypeName(pstate, typename);
if (!OidIsValid(typoid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist",
- TypeNameToString(typename))));
+ TypeNameToString(typename)),
+ parser_errposition(pstate, typename->location)));
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typoid),
0, 0, 0);
@@ -235,7 +244,8 @@ typenameType(const TypeName *typename)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" is only a shell",
- TypeNameToString(typename))));
+ TypeNameToString(typename)),
+ parser_errposition(pstate, typename->location)));
return (Type) tup;
}
@@ -447,7 +457,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
if (typename->setof)
goto fail;
- *type_id = typenameTypeId(typename);
+ *type_id = typenameTypeId(NULL, typename);
*typmod = typename->typmod;
pfree(buf.data);
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 3d63cb73c8..0ac8d346a7 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -24,7 +24,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.132 2006/03/07 01:00:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.133 2006/03/14 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -74,20 +74,19 @@ static int literalalloc; /* current allocated buffer size */
static void addlit(char *ytext, int yleng);
static void addlitchar(unsigned char ychar);
static char *litbufdup(void);
-static int pg_err_position(void);
+
+static int lexer_errposition(void);
static void check_escape_warning(void);
static void check_string_escape_warning(unsigned char ychar);
/*
+ * Each call to yylex must set yylloc to the location of the found token
+ * (expressed as a byte offset from the start of the input text).
* When we parse a token that requires multiple lexer rules to process,
- * we set token_start to point at the true start of the token, for use
- * by yyerror(). yytext will point at just the text consumed by the last
- * rule, so it's not very helpful (e.g., it might contain just the last
- * quote mark of a quoted identifier). But to avoid cluttering every rule
- * with setting token_start, we allow token_start = NULL to denote that
- * it's okay to use yytext.
+ * this should be done in the first such rule, else yylloc will point
+ * into the middle of the token.
*/
-static char *token_start;
+#define SET_YYLLOC() (yylloc = yytext - scanbuf)
/* Handles to the buffer that the lexer uses internally */
static YY_BUFFER_STATE scanbufhandle;
@@ -316,17 +315,13 @@ other .
%%
-%{
- /* code to execute during start of each call of yylex() */
- token_start = NULL;
-%}
-
{whitespace} {
/* ignore */
}
{xcstart} {
- token_start = yytext;
+ /* Set location in case of syntax error in comment */
+ SET_YYLLOC();
xcdepth = 0;
BEGIN(xc);
/* Put back any characters past slash-star; see above */
@@ -341,11 +336,7 @@ other .
<xc>{xcstop} {
if (xcdepth <= 0)
- {
BEGIN(INITIAL);
- /* reset token_start for next token */
- token_start = NULL;
- }
else
xcdepth--;
}
@@ -371,7 +362,7 @@ other .
* In the meantime, place a leading "b" on the string
* to mark it for the input routine as a binary string.
*/
- token_start = yytext;
+ SET_YYLLOC();
BEGIN(xb);
startlit();
addlitchar('b');
@@ -400,7 +391,7 @@ other .
* In the meantime, place a leading "x" on the string
* to mark it for the input routine as a hex string.
*/
- token_start = yytext;
+ SET_YYLLOC();
BEGIN(xh);
startlit();
addlitchar('x');
@@ -421,6 +412,7 @@ other .
*/
const ScanKeyword *keyword;
+ SET_YYLLOC();
yyless(1); /* eat only 'n' this time */
/* nchar had better be a keyword! */
keyword = ScanKeywordLookup("nchar");
@@ -431,7 +423,7 @@ other .
{xqstart} {
warn_on_first_escape = true;
- token_start = yytext;
+ SET_YYLLOC();
if (standard_conforming_strings)
BEGIN(xq);
else
@@ -440,7 +432,7 @@ other .
}
{xestart} {
warn_on_first_escape = false;
- token_start = yytext;
+ SET_YYLLOC();
BEGIN(xe);
startlit();
}
@@ -490,7 +482,7 @@ other .
<xq,xe><<EOF>> { yyerror("unterminated quoted string"); }
{dolqdelim} {
- token_start = yytext;
+ SET_YYLLOC();
dolqstart = pstrdup(yytext);
BEGIN(xdolq);
startlit();
@@ -533,7 +525,7 @@ other .
<xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
{xdstart} {
- token_start = yytext;
+ SET_YYLLOC();
BEGIN(xd);
startlit();
}
@@ -558,10 +550,12 @@ other .
<xd><<EOF>> { yyerror("unterminated quoted identifier"); }
{typecast} {
+ SET_YYLLOC();
return TYPECAST;
}
{self} {
+ SET_YYLLOC();
return yytext[0];
}
@@ -611,6 +605,8 @@ other .
nchars--; /* else remove the +/-, and check again */
}
+ SET_YYLLOC();
+
if (nchars < yyleng)
{
/* Strip the unwanted chars from the token */
@@ -644,6 +640,7 @@ other .
}
{param} {
+ SET_YYLLOC();
yylval.ival = atol(yytext + 1);
return PARAM;
}
@@ -652,6 +649,7 @@ other .
long val;
char* endptr;
+ SET_YYLLOC();
errno = 0;
val = strtol(yytext, &endptr, 10);
if (*endptr != '\0' || errno == ERANGE
@@ -669,10 +667,12 @@ other .
return ICONST;
}
{decimal} {
+ SET_YYLLOC();
yylval.str = pstrdup(yytext);
return FCONST;
}
{real} {
+ SET_YYLLOC();
yylval.str = pstrdup(yytext);
return FCONST;
}
@@ -684,12 +684,14 @@ other .
* syntax error anyway, we don't bother to distinguish.
*/
yyless(yyleng-1);
+ SET_YYLLOC();
yylval.str = pstrdup(yytext);
return FCONST;
}
{realfail2} {
/* throw back the [Ee][+-], and proceed as above */
yyless(yyleng-2);
+ SET_YYLLOC();
yylval.str = pstrdup(yytext);
return FCONST;
}
@@ -699,6 +701,8 @@ other .
const ScanKeyword *keyword;
char *ident;
+ SET_YYLLOC();
+
/* Is it a keyword? */
keyword = ScanKeywordLookup(yytext);
if (keyword != NULL)
@@ -717,25 +721,52 @@ other .
}
{other} {
+ SET_YYLLOC();
return yytext[0];
}
+<<EOF>> {
+ SET_YYLLOC();
+ yyterminate();
+ }
+
%%
+/*
+ * lexer_errposition
+ * Report a lexical-analysis-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call. The return value
+ * is a dummy (always 0, in fact).
+ *
+ * Note that this can only be used for messages from the lexer itself,
+ * since it depends on scanbuf to still be valid.
+ */
static int
-pg_err_position(void)
+lexer_errposition(void)
{
- const char *loc = token_start ? token_start : yytext;
+ int pos;
- /* in multibyte encodings, return index in characters not bytes */
- return pg_mbstrlen_with_len(scanbuf, loc - scanbuf) + 1;
+ /* Convert byte offset to character number */
+ pos = pg_mbstrlen_with_len(scanbuf, yylloc) + 1;
+ /* And pass it to the ereport mechanism */
+ return errposition(pos);
}
+/*
+ * yyerror
+ * Report a lexer or grammar error.
+ *
+ * The message's cursor position identifies the most recently lexed token.
+ * This is OK for syntax error messages from the Bison parser, because Bison
+ * parsers report error as soon as the first unparsable token is reached.
+ * Beware of using yyerror for other purposes, as the cursor position might
+ * be misleading!
+ */
void
yyerror(const char *message)
{
- const char *loc = token_start ? token_start : yytext;
- int cursorpos = pg_err_position();
+ const char *loc = scanbuf + yylloc;
if (*loc == YY_END_OF_BUFFER_CHAR)
{
@@ -743,7 +774,7 @@ yyerror(const char *message)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is typically "syntax error" */
errmsg("%s at end of input", _(message)),
- errposition(cursorpos)));
+ lexer_errposition()));
}
else
{
@@ -751,7 +782,7 @@ yyerror(const char *message)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: first %s is typically "syntax error" */
errmsg("%s at or near \"%s\"", _(message), loc),
- errposition(cursorpos)));
+ lexer_errposition()));
}
}
@@ -878,7 +909,7 @@ check_string_escape_warning(unsigned char ychar)
(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
errmsg("nonstandard use of \\' in a string literal"),
errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
- errposition(pg_err_position())));
+ lexer_errposition()));
warn_on_first_escape = false; /* warn only once per string */
}
else if (ychar == '\\')
@@ -888,7 +919,7 @@ check_string_escape_warning(unsigned char ychar)
(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
errmsg("nonstandard use of \\\\ in a string literal"),
errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
- errposition(pg_err_position())));
+ lexer_errposition()));
warn_on_first_escape = false; /* warn only once per string */
}
else
@@ -903,6 +934,6 @@ check_escape_warning(void)
(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
errmsg("nonstandard use of escape in a string literal"),
errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."),
- errposition(pg_err_position())));
+ lexer_errposition()));
warn_on_first_escape = false; /* warn only once per string */
}