diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index 35b0699..4e3e3e7 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -23,9 +23,9 @@ PostgreSQL documentation [ WITH [ RECURSIVE ] with_query [, ...] ] UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ] - SET { column_name = { expression | DEFAULT } | - ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | - ( column_name [, ...] ) = ( sub-SELECT ) + SET { [table_name.] column_name = { expression | DEFAULT } | + ( [table_name.] column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | + ( [table_name.] column_name [, ...] ) = ( sub-SELECT ) } [, ...] [ FROM from_list ] [ WHERE condition | WHERE CURRENT OF cursor_name ] diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 7d2fedf..f35ed22 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -65,7 +65,7 @@ static void determineRecursiveColTypes(ParseState *pstate, static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); static List *transformReturningList(ParseState *pstate, List *returningList); static List *transformUpdateTargetList(ParseState *pstate, - List *targetList); + List *targetList, RangeVar *relation); static Query *transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt); static Query *transformExplainStmt(ParseState *pstate, @@ -976,7 +976,7 @@ transformOnConflictClause(ParseState *pstate, false, true, true); onConflictSet = - transformUpdateTargetList(pstate, onConflictClause->targetList); + transformUpdateTargetList(pstate, onConflictClause->targetList, NULL); onConflictWhere = transformWhereClause(pstate, onConflictClause->whereClause, @@ -2094,7 +2094,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) * Now we are done with SELECT-like processing, and can get on with * transforming the target list to match the UPDATE target columns. */ - qry->targetList = transformUpdateTargetList(pstate, stmt->targetList); + qry->targetList = transformUpdateTargetList(pstate, stmt->targetList, stmt->relation); qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, qual); @@ -2111,7 +2111,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) * handle SET clause in UPDATE/INSERT ... ON CONFLICT UPDATE */ static List * -transformUpdateTargetList(ParseState *pstate, List *origTlist) +transformUpdateTargetList(ParseState *pstate, List *origTlist, RangeVar *relation) { List *tlist = NIL; RangeTblEntry *target_rte; @@ -2134,6 +2134,7 @@ transformUpdateTargetList(ParseState *pstate, List *origTlist) TargetEntry *tle = (TargetEntry *) lfirst(tl); ResTarget *origTarget; int attrno; + char *colname_temp = NULL; if (tle->resjunk) { @@ -2154,18 +2155,67 @@ transformUpdateTargetList(ParseState *pstate, List *origTlist) attrno = attnameAttNum(pstate->p_target_relation, origTarget->name, true); + + if(attrno == InvalidAttrNumber && relation) + { + if(origTarget->indirection) + { + colname_temp = strVal(lfirst(list_head(origTarget->indirection))); + + if(relation->alias) + { + if(relation->alias->aliasname) + { + if(strcmp(origTarget->name, relation->alias->aliasname) && strcmp(origTarget->name, relation->relname)) + ereport(ERROR,(errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("Perhaps you meant to reference the table alias \"%s\".", + relation->alias->aliasname))); + else + { + if(colname_temp) + attrno = attnameAttNum(pstate->p_target_relation, + colname_temp, true); + } + } + } + else + { + if(strcmp(origTarget->name, relation->relname) == 0) + { + if(colname_temp) + attrno = attnameAttNum(pstate->p_target_relation, + colname_temp, true); + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname_temp, origTarget->name), + parser_errposition(pstate, origTarget->location))); + } + } + + } + 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)), + colname_temp?colname_temp:origTarget->name, + colname_temp?origTarget->name:RelationGetRelationName(pstate->p_target_relation)), parser_errposition(pstate, origTarget->location))); - updateTargetListEntry(pstate, tle, origTarget->name, + + if(NULL == colname_temp) + updateTargetListEntry(pstate, tle, origTarget->name, attrno, origTarget->indirection, origTarget->location); + else + updateTargetListEntry(pstate, tle, colname_temp, + attrno, + NULL, + origTarget->location); /* Mark the target column as requiring update permissions */ target_rte->updatedCols = bms_add_member(target_rte->updatedCols, diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index adc1fd7..e7e5843 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -182,3 +182,44 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a) DROP TABLE update_test; DROP TABLE upsert_test; +CREATE TABLE update_test1 ( + a INT, + b INT, + c TEXT +); +INSERT INTO update_test1 VALUES (1, 10, 'aa'),(2, 11, 'bb'),(3, 12, 'cc'),(4, 13, 'dd'); +SELECT * FROM update_test1; + a | b | c +---+----+---- + 1 | 10 | aa + 2 | 11 | bb + 3 | 12 | cc + 4 | 13 | dd +(4 rows) + +UPDATE update_test1 SET tb1.a = 4 WHERE a = 1; +ERROR: column "a" of relation "tb1" does not exist +LINE 1: UPDATE update_test1 SET tb1.a = 4 WHERE a = 1; + ^ +UPDATE update_test1 tb1 SET tb1.f = 4 WHERE tb1.a = 1; +ERROR: column "f" of relation "tb1" does not exist +LINE 1: UPDATE update_test1 tb1 SET tb1.f = 4 WHERE tb1.a = 1; + ^ +UPDATE update_test1 tb SET tb1.a = 4 WHERE tb.a = 1; +ERROR: Perhaps you meant to reference the table alias "tb". +UPDATE update_test1 tb SET tb1.f = 4 WHERE tb.a = 1; +ERROR: Perhaps you meant to reference the table alias "tb". +UPDATE update_test1 tb1 SET tb1.a = 5 WHERE tb1.a = 1; +UPDATE update_test1 tb1 SET update_test1.a = 6 WHERE tb1.a = 2; +UPDATE update_test1 SET update_test1.a = 7 WHERE a = 3; +UPDATE update_test1 tb1 SET a = 8 WHERE a = 4; +SELECT * FROM update_test1; + a | b | c +---+----+---- + 5 | 10 | aa + 6 | 11 | bb + 7 | 12 | cc + 8 | 13 | dd +(4 rows) + +DROP TABLE update_test1; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index 5637c68..ab59fc2 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -96,3 +96,26 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a) DROP TABLE update_test; DROP TABLE upsert_test; + +CREATE TABLE update_test1 ( + a INT, + b INT, + c TEXT +); + +INSERT INTO update_test1 VALUES (1, 10, 'aa'),(2, 11, 'bb'),(3, 12, 'cc'),(4, 13, 'dd'); + +SELECT * FROM update_test1; + +UPDATE update_test1 SET tb1.a = 4 WHERE a = 1; +UPDATE update_test1 tb1 SET tb1.f = 4 WHERE tb1.a = 1; +UPDATE update_test1 tb SET tb1.a = 4 WHERE tb.a = 1; +UPDATE update_test1 tb SET tb1.f = 4 WHERE tb.a = 1; + +UPDATE update_test1 tb1 SET tb1.a = 5 WHERE tb1.a = 1; +UPDATE update_test1 tb1 SET update_test1.a = 6 WHERE tb1.a = 2; +UPDATE update_test1 SET update_test1.a = 7 WHERE a = 3; +UPDATE update_test1 tb1 SET a = 8 WHERE a = 4; +SELECT * FROM update_test1; + +DROP TABLE update_test1;