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:
@ -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
|
||||
*****************************************************************************/
|
||||
|
Reference in New Issue
Block a user