aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c89
-rw-r--r--src/backend/parser/gram.y20
-rw-r--r--src/backend/parser/keywords.c3
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},