Commit 19956e0d authored by Tom Lane's avatar Tom Lane

Add error location info to ResTarget parse nodes. Allows error cursor to be supplied

for various mistakes involving INSERT and UPDATE target columns.
parent a3f0b3d6
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.92 2006/03/05 15:58:23 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.93 2006/03/23 00:19:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -216,6 +216,11 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
char *col = strVal(lfirst(le));
i = attnameAttNum(onerel, col, false);
if (i == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
col, RelationGetRelationName(onerel))));
vacattrstats[tcnt] = examine_attribute(onerel, i);
if (vacattrstats[tcnt] != NULL)
tcnt++;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.260 2006/03/05 15:58:23 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.261 2006/03/23 00:19:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -3109,9 +3109,14 @@ CopyGetAttnums(Relation rel, List *attnamelist)
char *name = strVal(lfirst(l));
int attnum;
/* Lookup column name, ereport on failure */
/* Lookup column name */
/* Note we disallow system columns here */
attnum = attnameAttNum(rel, name, false);
if (attnum == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
name, RelationGetRelationName(rel))));
/* Check for duplicates */
if (list_member_int(attnums, attnum))
ereport(ERROR,
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.331 2006/03/16 00:31:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.332 2006/03/23 00:19:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1520,6 +1520,7 @@ _copyResTarget(ResTarget *from)
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(indirection);
COPY_NODE_FIELD(val);
COPY_SCALAR_FIELD(location);
return newnode;
}
......
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.267 2006/03/16 00:31:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.268 2006/03/23 00:19:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1608,6 +1608,7 @@ _equalResTarget(ResTarget *a, ResTarget *b)
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(indirection);
COMPARE_NODE_FIELD(val);
COMPARE_SCALAR_FIELD(location);
return true;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.271 2006/03/16 00:31:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.272 2006/03/23 00:19:29 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -1738,6 +1738,7 @@ _outResTarget(StringInfo str, ResTarget *node)
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(indirection);
WRITE_NODE_FIELD(val);
WRITE_INT_FIELD(location);
}
static void
......
......@@ -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.331 2006/03/14 22:48:20 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.332 2006/03/23 00:19:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -700,7 +700,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
Assert(!tle->resjunk);
updateTargetListEntry(pstate, tle, col->name, lfirst_int(attnos),
col->indirection);
col->indirection, col->location);
icols = lnext(icols);
attnos = lnext(attnos);
......@@ -2360,6 +2360,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
ResTarget *origTarget;
int attrno;
if (tle->resjunk)
{
......@@ -2378,10 +2379,20 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
origTarget = (ResTarget *) lfirst(origTargetList);
Assert(IsA(origTarget, ResTarget));
attrno = attnameAttNum(pstate->p_target_relation,
origTarget->name, true);
if (attrno == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
origTarget->name,
RelationGetRelationName(pstate->p_target_relation)),
parser_errposition(pstate, origTarget->location)));
updateTargetListEntry(pstate, tle, origTarget->name,
attnameAttNum(pstate->p_target_relation,
origTarget->name, true),
origTarget->indirection);
attrno,
origTarget->indirection,
origTarget->location);
origTargetList = lnext(origTargetList);
}
......
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.536 2006/03/14 23:03:20 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.537 2006/03/23 00:19:29 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -5187,6 +5187,7 @@ insert_column_item:
$$->name = $1;
$$->indirection = $2;
$$->val = NULL;
$$->location = @1;
}
;
......@@ -7918,6 +7919,7 @@ target_el: a_expr AS ColLabel
$$->name = $3;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| a_expr
{
......@@ -7925,6 +7927,7 @@ target_el: a_expr AS ColLabel
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| '*'
{
......@@ -7936,6 +7939,7 @@ target_el: a_expr AS ColLabel
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)n;
$$->location = @1;
}
;
......@@ -7951,6 +7955,7 @@ update_target_el:
$$->name = $1;
$$->indirection = $2;
$$->val = (Node *) $4;
$$->location = @1;
}
| ColId opt_indirection '=' DEFAULT
{
......@@ -7958,6 +7963,7 @@ update_target_el:
$$->name = $1;
$$->indirection = $2;
$$->val = (Node *) makeNode(SetToDefault);
$$->location = @1;
}
;
......@@ -7974,6 +7980,7 @@ insert_target_el:
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| DEFAULT
{
......@@ -7981,6 +7988,7 @@ insert_target_el:
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *) makeNode(SetToDefault);
$$->location = @1;
}
;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.121 2006/03/16 00:31:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.122 2006/03/23 00:19:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1703,7 +1703,9 @@ get_tle_by_resno(List *tlist, AttrNumber resno)
}
/*
* given relation and att name, return id of variable
* given relation and att name, return attnum of variable
*
* Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_attnum()
......@@ -1732,11 +1734,7 @@ attnameAttNum(Relation rd, const char *attname, bool sysColOK)
}
/* on failure */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
attname, RelationGetRelationName(rd))));
return InvalidAttrNumber; /* keep compiler quiet */
return InvalidAttrNumber;
}
/* specialAttNum()
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.141 2006/03/14 22:48:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.142 2006/03/23 00:19:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -40,7 +40,8 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
Oid targetTypeId,
int32 targetTypMod,
ListCell *indirection,
Node *rhs);
Node *rhs,
int location);
static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref);
static List *ExpandAllTables(ParseState *pstate);
static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind);
......@@ -247,13 +248,15 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
* colname target column name (ie, name of attribute to be assigned to)
* attrno target attribute number
* indirection subscripts/field names for target column, if any
* location error cursor position (should point at column name), or -1
*/
void
updateTargetListEntry(ParseState *pstate,
TargetEntry *tle,
char *colname,
int attrno,
List *indirection)
List *indirection,
int location)
{
Oid type_id; /* type of value provided */
Oid attrtype; /* type of target column */
......@@ -265,7 +268,8 @@ updateTargetListEntry(ParseState *pstate,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot assign to system column \"%s\"",
colname)));
colname),
parser_errposition(pstate, location)));
attrtype = attnumTypeId(rd, attrno);
attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
......@@ -288,11 +292,13 @@ updateTargetListEntry(ParseState *pstate,
if (IsA(linitial(indirection), A_Indices))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot set an array element to DEFAULT")));
errmsg("cannot set an array element to DEFAULT"),
parser_errposition(pstate, location)));
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot set a subfield to DEFAULT")));
errmsg("cannot set a subfield to DEFAULT"),
parser_errposition(pstate, location)));
}
}
......@@ -336,7 +342,8 @@ updateTargetListEntry(ParseState *pstate,
attrtype,
attrtypmod,
list_head(indirection),
(Node *) tle->expr);
(Node *) tle->expr,
location);
}
else
{
......@@ -358,7 +365,8 @@ updateTargetListEntry(ParseState *pstate,
colname,
format_type_be(attrtype),
format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression.")));
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, location)));
}
/*
......@@ -395,6 +403,11 @@ updateTargetListEntry(ParseState *pstate,
*
* rhs is the already-transformed value to be assigned; note it has not been
* coerced to any particular type.
*
* location is the cursor error position for any errors. (Note: this points
* to the head of the target clause, eg "foo" in "foo.bar[baz]". Later we
* might want to decorate indirection cells with their own location info,
* in which case the location argument could probably be dropped.)
*/
static Node *
transformAssignmentIndirection(ParseState *pstate,
......@@ -404,7 +417,8 @@ transformAssignmentIndirection(ParseState *pstate,
Oid targetTypeId,
int32 targetTypMod,
ListCell *indirection,
Node *rhs)
Node *rhs,
int location)
{
Node *result;
List *subscripts = NIL;
......@@ -460,7 +474,8 @@ transformAssignmentIndirection(ParseState *pstate,
typeNeeded,
targetTypMod,
i,
rhs);
rhs,
location);
/* process subscripts */
return (Node *) transformArraySubscripts(pstate,
basenode,
......@@ -479,7 +494,8 @@ transformAssignmentIndirection(ParseState *pstate,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
strVal(n), targetName,
format_type_be(targetTypeId))));
format_type_be(targetTypeId)),
parser_errposition(pstate, location)));
attnum = get_attnum(typrelid, strVal(n));
if (attnum == InvalidAttrNumber)
......@@ -487,12 +503,14 @@ transformAssignmentIndirection(ParseState *pstate,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s",
strVal(n), targetName,
format_type_be(targetTypeId))));
format_type_be(targetTypeId)),
parser_errposition(pstate, location)));
if (attnum < 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("cannot assign to system column \"%s\"",
strVal(n))));
strVal(n)),
parser_errposition(pstate, location)));
get_atttypetypmod(typrelid, attnum,
&fieldTypeId, &fieldTypMod);
......@@ -505,7 +523,8 @@ transformAssignmentIndirection(ParseState *pstate,
fieldTypeId,
fieldTypMod,
lnext(i),
rhs);
rhs,
location);
/* and build a FieldStore node */
fstore = makeNode(FieldStore);
......@@ -532,7 +551,8 @@ transformAssignmentIndirection(ParseState *pstate,
typeNeeded,
targetTypMod,
NULL,
rhs);
rhs,
location);
/* process subscripts */
return (Node *) transformArraySubscripts(pstate,
basenode,
......@@ -560,7 +580,8 @@ transformAssignmentIndirection(ParseState *pstate,
targetName,
format_type_be(targetTypeId),
format_type_be(exprType(rhs))),
errhint("You will need to rewrite or cast the expression.")));
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, location)));
else
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
......@@ -569,7 +590,8 @@ transformAssignmentIndirection(ParseState *pstate,
targetName,
format_type_be(targetTypeId),
format_type_be(exprType(rhs))),
errhint("You will need to rewrite or cast the expression.")));
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, location)));
}
return result;
......@@ -607,6 +629,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
col->name = pstrdup(NameStr(attr[i]->attname));
col->indirection = NIL;
col->val = NULL;
col->location = -1;
cols = lappend(cols, col);
*attrnos = lappend_int(*attrnos, i + 1);
}
......@@ -628,6 +651,13 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
/* Lookup column name, ereport on failure */
attrno = attnameAttNum(pstate->p_target_relation, name, false);
if (attrno == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
name,
RelationGetRelationName(pstate->p_target_relation)),
parser_errposition(pstate, col->location)));
/*
* Check for duplicates, but only of whole columns --- we allow
......@@ -641,7 +671,8 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" specified more than once",
name)));
name),
parser_errposition(pstate, col->location)));
wholecols = bms_add_member(wholecols, attrno);
}
else
......@@ -651,7 +682,8 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" specified more than once",
name)));
name),
parser_errposition(pstate, col->location)));
partialcols = bms_add_member(partialcols, attrno);
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/not_in.c,v 1.44 2006/03/05 15:58:43 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/not_in.c,v 1.45 2006/03/23 00:19:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -72,6 +72,12 @@ int4notin(PG_FUNCTION_ARGS)
/* Find the column to search */
attrid = attnameAttNum(relation_to_scan, attribute, true);
if (attrid == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
attribute,
RelationGetRelationName(relation_to_scan))));
scan_descriptor = heap_beginscan(relation_to_scan, SnapshotNow,
0, (ScanKey) NULL);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.305 2006/03/16 00:31:55 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.306 2006/03/23 00:19:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -327,6 +327,7 @@ typedef struct ResTarget
char *name; /* column name or NULL */
List *indirection; /* subscripts and field names, or NIL */
Node *val; /* the value expression to compute or assign */
int location; /* token location, or -1 if unknown */
} ResTarget;
/*
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_target.h,v 1.38 2006/03/05 15:58:57 momjian Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_target.h,v 1.39 2006/03/23 00:19:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -24,7 +24,8 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
char *colname, bool resjunk);
extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
char *colname, int attrno,
List *indirection);
List *indirection,
int location);
extern List *checkInsertTargets(ParseState *pstate, List *cols,
List **attrnos);
extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
......
......@@ -677,12 +677,16 @@ LINE 1: select * from atacc1 where "........pg.dropped.1........" = ...
-- UPDATEs
update atacc1 set a = 3;
ERROR: column "a" of relation "atacc1" does not exist
LINE 1: update atacc1 set a = 3;
^
update atacc1 set b = 2 where a = 3;
ERROR: column "a" does not exist
LINE 1: update atacc1 set b = 2 where a = 3;
^
update atacc1 set "........pg.dropped.1........" = 3;
ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
LINE 1: update atacc1 set "........pg.dropped.1........" = 3;
^
update atacc1 set b = 2 where "........pg.dropped.1........" = 3;
ERROR: column "........pg.dropped.1........" does not exist
LINE 1: update atacc1 set b = 2 where "........pg.dropped.1........"...
......@@ -695,21 +699,37 @@ ERROR: INSERT has more expressions than target columns
insert into atacc1 values (11, 12, 13);
insert into atacc1 (a) values (10);
ERROR: column "a" of relation "atacc1" does not exist
LINE 1: insert into atacc1 (a) values (10);
^
insert into atacc1 (a) values (default);
ERROR: column "a" of relation "atacc1" does not exist
LINE 1: insert into atacc1 (a) values (default);
^
insert into atacc1 (a,b,c,d) values (10,11,12,13);
ERROR: column "a" of relation "atacc1" does not exist
LINE 1: insert into atacc1 (a,b,c,d) values (10,11,12,13);
^
insert into atacc1 (a,b,c,d) values (default,11,12,13);
ERROR: column "a" of relation "atacc1" does not exist
LINE 1: insert into atacc1 (a,b,c,d) values (default,11,12,13);
^
insert into atacc1 (b,c,d) values (11,12,13);
insert into atacc1 ("........pg.dropped.1........") values (10);
ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
LINE 1: insert into atacc1 ("........pg.dropped.1........") values (...
^
insert into atacc1 ("........pg.dropped.1........") values (default);
ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
LINE 1: insert into atacc1 ("........pg.dropped.1........") values (...
^
insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13);
ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
LINE 1: insert into atacc1 ("........pg.dropped.1........",b,c,d) va...
^
insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13);
ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
LINE 1: insert into atacc1 ("........pg.dropped.1........",b,c,d) va...
^
-- DELETEs
delete from atacc1 where a = 3;
ERROR: column "a" does not exist
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment