1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +03:00

Add INSERT/UPDATE/DELETE RETURNING, with basic docs and regression tests.

plpgsql support to come later.  Along the way, convert execMain's
SELECT INTO support into a DestReceiver, in order to eliminate some ugly
special cases.

Jonah Harris and Tom Lane
This commit is contained in:
Tom Lane
2006-08-12 02:52:06 +00:00
parent 5c9e9c0c42
commit 7a3e30e608
35 changed files with 1472 additions and 422 deletions

View File

@ -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 *

View File

@ -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

View File

@ -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},