1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +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

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.123 2006/08/02 01:59:46 joe Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.124 2006/08/12 02:52:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -42,7 +42,6 @@ typedef struct
typedef struct
{
List *rtable;
indexed_tlist *outer_itlist;
indexed_tlist *inner_itlist;
Index acceptable_rel;
@ -61,9 +60,8 @@ static void adjust_expr_varnos(Node *node, int rtoffset);
static bool adjust_expr_varnos_walker(Node *node, int *context);
static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context);
static void set_join_references(Join *join, List *rtable);
static void set_join_references(Join *join);
static void set_inner_join_references(Plan *inner_plan,
List *rtable,
indexed_tlist *outer_itlist);
static void set_uppernode_references(Plan *plan, Index subvarno);
static indexed_tlist *build_tlist_index(List *tlist);
@ -74,7 +72,6 @@ static Var *search_indexed_tlist_for_non_var(Node *node,
indexed_tlist *itlist,
Index newvarno);
static List *join_references(List *clauses,
List *rtable,
indexed_tlist *outer_itlist,
indexed_tlist *inner_itlist,
Index acceptable_rel);
@ -199,13 +196,13 @@ set_plan_references(Plan *plan, List *rtable)
}
break;
case T_NestLoop:
set_join_references((Join *) plan, rtable);
set_join_references((Join *) plan);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
break;
case T_MergeJoin:
set_join_references((Join *) plan, rtable);
set_join_references((Join *) plan);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
@ -213,7 +210,7 @@ set_plan_references(Plan *plan, List *rtable)
(Node *) ((MergeJoin *) plan)->mergeclauses);
break;
case T_HashJoin:
set_join_references((Join *) plan, rtable);
set_join_references((Join *) plan);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
@ -718,10 +715,9 @@ fix_expr_references_walker(Node *node, void *context)
* quals of the child indexscan. set_inner_join_references does that.
*
* 'join' is a join plan node
* 'rtable' is the associated range table
*/
static void
set_join_references(Join *join, List *rtable)
set_join_references(Join *join)
{
Plan *outer_plan = join->plan.lefttree;
Plan *inner_plan = join->plan.righttree;
@ -733,17 +729,14 @@ set_join_references(Join *join, List *rtable)
/* All join plans have tlist, qual, and joinqual */
join->plan.targetlist = join_references(join->plan.targetlist,
rtable,
outer_itlist,
inner_itlist,
(Index) 0);
join->plan.qual = join_references(join->plan.qual,
rtable,
outer_itlist,
inner_itlist,
(Index) 0);
join->joinqual = join_references(join->joinqual,
rtable,
outer_itlist,
inner_itlist,
(Index) 0);
@ -753,7 +746,6 @@ set_join_references(Join *join, List *rtable)
{
/* This processing is split out to handle possible recursion */
set_inner_join_references(inner_plan,
rtable,
outer_itlist);
}
else if (IsA(join, MergeJoin))
@ -761,7 +753,6 @@ set_join_references(Join *join, List *rtable)
MergeJoin *mj = (MergeJoin *) join;
mj->mergeclauses = join_references(mj->mergeclauses,
rtable,
outer_itlist,
inner_itlist,
(Index) 0);
@ -771,7 +762,6 @@ set_join_references(Join *join, List *rtable)
HashJoin *hj = (HashJoin *) join;
hj->hashclauses = join_references(hj->hashclauses,
rtable,
outer_itlist,
inner_itlist,
(Index) 0);
@ -791,9 +781,7 @@ set_join_references(Join *join, List *rtable)
* function so that it can recurse.
*/
static void
set_inner_join_references(Plan *inner_plan,
List *rtable,
indexed_tlist *outer_itlist)
set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
{
if (IsA(inner_plan, IndexScan))
{
@ -813,12 +801,10 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */
innerscan->indexqualorig = join_references(indexqualorig,
rtable,
outer_itlist,
NULL,
innerrel);
innerscan->indexqual = join_references(innerscan->indexqual,
rtable,
outer_itlist,
NULL,
innerrel);
@ -830,7 +816,6 @@ set_inner_join_references(Plan *inner_plan,
*/
if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual,
rtable,
outer_itlist,
NULL,
innerrel);
@ -851,12 +836,10 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */
innerscan->indexqualorig = join_references(indexqualorig,
rtable,
outer_itlist,
NULL,
innerrel);
innerscan->indexqual = join_references(innerscan->indexqual,
rtable,
outer_itlist,
NULL,
innerrel);
@ -880,7 +863,6 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */
if (NumRelids((Node *) bitmapqualorig) > 1)
innerscan->bitmapqualorig = join_references(bitmapqualorig,
rtable,
outer_itlist,
NULL,
innerrel);
@ -892,14 +874,12 @@ set_inner_join_references(Plan *inner_plan,
*/
if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual,
rtable,
outer_itlist,
NULL,
innerrel);
/* Now recurse */
set_inner_join_references(inner_plan->lefttree,
rtable,
outer_itlist);
}
else if (IsA(inner_plan, BitmapAnd))
@ -911,7 +891,6 @@ set_inner_join_references(Plan *inner_plan,
foreach(l, innerscan->bitmapplans)
{
set_inner_join_references((Plan *) lfirst(l),
rtable,
outer_itlist);
}
}
@ -924,7 +903,6 @@ set_inner_join_references(Plan *inner_plan,
foreach(l, innerscan->bitmapplans)
{
set_inner_join_references((Plan *) lfirst(l),
rtable,
outer_itlist);
}
}
@ -940,7 +918,6 @@ set_inner_join_references(Plan *inner_plan,
foreach(l, appendplan->appendplans)
{
set_inner_join_references((Plan *) lfirst(l),
rtable,
outer_itlist);
}
}
@ -950,7 +927,6 @@ set_inner_join_references(Plan *inner_plan,
Index innerrel = innerscan->scan.scanrelid;
innerscan->tidquals = join_references(innerscan->tidquals,
rtable,
outer_itlist,
NULL,
innerrel);
@ -1061,6 +1037,52 @@ build_tlist_index(List *tlist)
return itlist;
}
/*
* build_tlist_index_other_vars --- build a restricted tlist index
*
* This is like build_tlist_index, but we only index tlist entries that
* are Vars and belong to some rel other than the one specified.
*/
static indexed_tlist *
build_tlist_index_other_vars(List *tlist, Index ignore_rel)
{
indexed_tlist *itlist;
tlist_vinfo *vinfo;
ListCell *l;
/* Create data structure with enough slots for all tlist entries */
itlist = (indexed_tlist *)
palloc(offsetof(indexed_tlist, vars) +
list_length(tlist) * sizeof(tlist_vinfo));
itlist->tlist = tlist;
itlist->has_non_vars = false;
/* Find the desired Vars and fill in the index array */
vinfo = itlist->vars;
foreach(l, tlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->expr && IsA(tle->expr, Var))
{
Var *var = (Var *) tle->expr;
if (var->varno != ignore_rel)
{
vinfo->varno = var->varno;
vinfo->varattno = var->varattno;
vinfo->resno = tle->resno;
vinfo++;
}
}
}
itlist->num_vars = (vinfo - itlist->vars);
return itlist;
}
/*
* search_indexed_tlist_for_var --- find a Var in an indexed tlist
*
@ -1137,14 +1159,14 @@ search_indexed_tlist_for_non_var(Node *node,
* all the Vars in the clause *must* be replaced by OUTER or INNER references;
* and an indexscan being used on the inner side of a nestloop join.
* In the latter case we want to replace the outer-relation Vars by OUTER
* references, but not touch the Vars of the inner relation.
* references, but not touch the Vars of the inner relation. (We also
* implement RETURNING clause fixup using this second scenario.)
*
* For a normal join, acceptable_rel should be zero so that any failure to
* match a Var will be reported as an error. For the indexscan case,
* pass inner_itlist = NULL and acceptable_rel = the ID of the inner relation.
*
* 'clauses' is the targetlist or list of join clauses
* 'rtable' is the current range table
* 'outer_itlist' is the indexed target list of the outer join relation
* 'inner_itlist' is the indexed target list of the inner join relation,
* or NULL
@ -1156,14 +1178,12 @@ search_indexed_tlist_for_non_var(Node *node,
*/
static List *
join_references(List *clauses,
List *rtable,
indexed_tlist *outer_itlist,
indexed_tlist *inner_itlist,
Index acceptable_rel)
{
join_references_context context;
context.rtable = rtable;
context.outer_itlist = outer_itlist;
context.inner_itlist = inner_itlist;
context.acceptable_rel = acceptable_rel;
@ -1295,6 +1315,53 @@ replace_vars_with_subplan_refs_mutator(Node *node,
(void *) context);
}
/*
* set_returning_clause_references
* Perform setrefs.c's work on a RETURNING targetlist
*
* If the query involves more than just the result table, we have to
* adjust any Vars that refer to other tables to reference junk tlist
* entries in the top plan's targetlist. Vars referencing the result
* table should be left alone, however (the executor will evaluate them
* using the actual heap tuple, after firing triggers if any). In the
* adjusted RETURNING list, result-table Vars will still have their
* original varno, but Vars for other rels will have varno OUTER.
*
* We also must apply fix_expr_references to the list.
*
* 'rlist': the RETURNING targetlist to be fixed
* 'topplan': the top Plan node for the query (not yet passed through
* set_plan_references)
* 'resultRelation': RT index of the query's result relation
*/
List *
set_returning_clause_references(List *rlist,
Plan *topplan,
Index resultRelation)
{
indexed_tlist *itlist;
/*
* We can perform the desired Var fixup by abusing the join_references
* machinery that normally handles inner indexscan fixup. We search
* the top plan's targetlist for Vars of non-result relations, and use
* join_references to convert RETURNING Vars into references to those
* tlist entries, while leaving result-rel Vars as-is.
*/
itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
rlist = join_references(rlist,
itlist,
NULL,
resultRelation);
fix_expr_references(topplan, (Node *) rlist);
pfree(itlist);
return rlist;
}
/*****************************************************************************
* OPERATOR REGPROC LOOKUP
*****************************************************************************/