diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 89 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 20 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 3 |
3 files changed, 99 insertions, 13 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 6921e1d77c8..61242ef712e 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.344 2006/08/10 02:36:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.345 2006/08/12 02:52:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -100,6 +100,7 @@ static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt, List **extras_before, List **extras_after); static List *transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos); +static List *transformReturningList(ParseState *pstate, List *returningList); static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt); static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt, List **extras_before, List **extras_after); @@ -494,9 +495,10 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) */ transformFromClause(pstate, stmt->usingClause); - /* fix where clause */ qual = transformWhereClause(pstate, stmt->whereClause, "WHERE"); + qry->returningList = transformReturningList(pstate, stmt->returningList); + /* done building the range table and jointree */ qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, qual); @@ -820,6 +822,22 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, attnos = lnext(attnos); } + /* + * If we have a RETURNING clause, we need to add the target relation + * to the query namespace before processing it, so that Var references + * in RETURNING will work. Also, remove any namespace entries added + * in a sub-SELECT or VALUES list. + */ + if (stmt->returningList) + { + pstate->p_relnamespace = NIL; + pstate->p_varnamespace = NIL; + addRTEtoQuery(pstate, pstate->p_target_rangetblentry, + false, true, true); + qry->returningList = transformReturningList(pstate, + stmt->returningList); + } + /* done building the range table and jointree */ qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, NULL); @@ -1297,7 +1315,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, if (including_indexes) elog(ERROR, "TODO"); - + /* * Insert the inherited attributes into the cxt for the new table * definition. @@ -1368,11 +1386,11 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, def->cooked_default = pstrdup(this_default); } } - + if (including_constraints && tupleDesc->constr) { int ccnum; AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns); - + for(ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++) { char *ccname = tupleDesc->constr->check[ccnum].ccname; char *ccbin = tupleDesc->constr->check[ccnum].ccbin; @@ -1380,7 +1398,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, Constraint *n = makeNode(Constraint); change_varattnos_of_a_node(ccbin_node, attmap); - + n->contype = CONSTR_CHECK; n->name = pstrdup(ccname); n->raw_expr = ccbin_node; @@ -2777,6 +2795,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) qual = transformWhereClause(pstate, stmt->whereClause, "WHERE"); + qry->returningList = transformReturningList(pstate, stmt->returningList); + qry->rtable = pstate->p_rtable; qry->jointree = makeFromExpr(pstate->p_joinlist, qual); @@ -2851,7 +2871,62 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) } /* - * tranformAlterTableStmt - + * transformReturningList - + * handle a RETURNING clause in INSERT/UPDATE/DELETE + */ +static List * +transformReturningList(ParseState *pstate, List *returningList) +{ + List *rlist; + int save_next_resno; + bool save_hasAggs; + int length_rtable; + + if (returningList == NIL) + return NIL; /* nothing to do */ + + /* + * We need to assign resnos starting at one in the RETURNING list. + * Save and restore the main tlist's value of p_next_resno, just in + * case someone looks at it later (probably won't happen). + */ + save_next_resno = pstate->p_next_resno; + pstate->p_next_resno = 1; + + /* save other state so that we can detect disallowed stuff */ + save_hasAggs = pstate->p_hasAggs; + pstate->p_hasAggs = false; + length_rtable = list_length(pstate->p_rtable); + + /* transform RETURNING identically to a SELECT targetlist */ + rlist = transformTargetList(pstate, returningList); + + /* check for disallowed stuff */ + + /* aggregates not allowed (but subselects are okay) */ + if (pstate->p_hasAggs) + ereport(ERROR, + (errcode(ERRCODE_GROUPING_ERROR), + errmsg("cannot use aggregate function in RETURNING"))); + + /* no new relation references please */ + if (list_length(pstate->p_rtable) != length_rtable) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("RETURNING may not contain references to other relations"))); + + /* mark column origins */ + markTargetListOrigins(pstate, rlist); + + /* restore state */ + pstate->p_next_resno = save_next_resno; + pstate->p_hasAggs = save_hasAggs; + + return rlist; +} + +/* + * transformAlterTableStmt - * transform an Alter Table Statement */ static Query * diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4586c77f8a1..389c594c8bc 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.554 2006/08/02 01:59:46 joe Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.555 2006/08/12 02:52:05 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -244,7 +244,7 @@ static void doNegateFloat(Value *v); transaction_mode_list_or_empty TableFuncElementList prep_type_clause prep_type_list - execute_param_clause using_clause + execute_param_clause using_clause returning_clause %type <range> into_clause OptTempTableName @@ -412,7 +412,7 @@ static void doNegateFloat(Value *v); QUOTE READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME - REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT + REPEATABLE REPLACE RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE @@ -5334,9 +5334,10 @@ DeallocateStmt: DEALLOCATE name *****************************************************************************/ InsertStmt: - INSERT INTO qualified_name insert_rest + INSERT INTO qualified_name insert_rest returning_clause { $4->relation = $3; + $4->returningList = $5; $$ = (Node *) $4; } ; @@ -5380,6 +5381,11 @@ insert_column_item: } ; +returning_clause: + RETURNING target_list { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + /***************************************************************************** * @@ -5389,12 +5395,13 @@ insert_column_item: *****************************************************************************/ DeleteStmt: DELETE_P FROM relation_expr_opt_alias - using_clause where_clause + using_clause where_clause returning_clause { DeleteStmt *n = makeNode(DeleteStmt); n->relation = $3; n->usingClause = $4; n->whereClause = $5; + n->returningList = $6; $$ = (Node *)n; } ; @@ -5445,12 +5452,14 @@ UpdateStmt: UPDATE relation_expr_opt_alias SET update_target_list from_clause where_clause + returning_clause { UpdateStmt *n = makeNode(UpdateStmt); n->relation = $2; n->targetList = $4; n->fromClause = $5; n->whereClause = $6; + n->returningList = $7; $$ = (Node *)n; } ; @@ -8809,6 +8818,7 @@ reserved_keyword: | PLACING | PRIMARY | REFERENCES + | RETURNING | SELECT | SESSION_USER | SOME diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 37686873f62..e799d68ae69 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.174 2006/07/31 01:16:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.175 2006/08/12 02:52:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -284,6 +284,7 @@ static const ScanKeyword ScanKeywords[] = { {"reset", RESET}, {"restart", RESTART}, {"restrict", RESTRICT}, + {"returning", RETURNING}, {"returns", RETURNS}, {"revoke", REVOKE}, {"right", RIGHT}, |