aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/plan/planagg.c3
-rw-r--r--src/backend/optimizer/plan/planner.c39
-rw-r--r--src/backend/optimizer/plan/setrefs.c137
-rw-r--r--src/backend/optimizer/prep/prepjointree.c6
-rw-r--r--src/backend/optimizer/prep/preptlist.c39
-rw-r--r--src/backend/optimizer/util/clauses.c5
6 files changed, 185 insertions, 44 deletions
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 849b81a9a75..2baf8e391d6 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.20 2006/07/27 19:52:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.21 2006/08/12 02:52:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -439,6 +439,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
subparse->commandType = CMD_SELECT;
subparse->resultRelation = 0;
subparse->resultRelations = NIL;
+ subparse->returningLists = NIL;
subparse->into = NULL;
subparse->hasAggs = false;
subparse->groupClause = NIL;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0eeaff064ff..f8eb95baf43 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.207 2006/08/05 17:21:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.208 2006/08/12 02:52:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -280,6 +280,10 @@ subquery_planner(Query *parse, double tuple_fraction,
preprocess_expression(root, (Node *) parse->targetList,
EXPRKIND_TARGET);
+ parse->returningList = (List *)
+ preprocess_expression(root, (Node *) parse->returningList,
+ EXPRKIND_TARGET);
+
preprocess_qual_conditions(root, (Node *) parse->jointree);
parse->havingQual = preprocess_expression(root, parse->havingQual,
@@ -554,13 +558,13 @@ inheritance_planner(PlannerInfo *root)
Query *parse = root->parse;
int parentRTindex = parse->resultRelation;
List *subplans = NIL;
+ List *resultRelations = NIL;
+ List *returningLists = NIL;
List *rtable = NIL;
List *tlist = NIL;
PlannerInfo subroot;
ListCell *l;
- parse->resultRelations = NIL;
-
foreach(l, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
@@ -605,10 +609,20 @@ inheritance_planner(PlannerInfo *root)
subplans = lappend(subplans, subplan);
/* Build target-relations list for the executor */
- parse->resultRelations = lappend_int(parse->resultRelations,
- appinfo->child_relid);
+ resultRelations = lappend_int(resultRelations, appinfo->child_relid);
+
+ /* Build list of per-relation RETURNING targetlists */
+ if (parse->returningList)
+ {
+ Assert(list_length(subroot.parse->returningLists) == 1);
+ returningLists = list_concat(returningLists,
+ subroot.parse->returningLists);
+ }
}
+ parse->resultRelations = resultRelations;
+ parse->returningLists = returningLists;
+
/* Mark result as unordered (probably unnecessary) */
root->query_pathkeys = NIL;
@@ -1083,6 +1097,21 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
}
/*
+ * Deal with the RETURNING clause if any. It's convenient to pass the
+ * returningList through setrefs.c now rather than at top level (if
+ * we waited, handling inherited UPDATE/DELETE would be much harder).
+ */
+ if (parse->returningList)
+ {
+ List *rlist;
+
+ rlist = set_returning_clause_references(parse->returningList,
+ result_plan,
+ parse->resultRelation);
+ parse->returningLists = list_make1(rlist);
+ }
+
+ /*
* Return the actual output ordering in query_pathkeys for possible use by
* an outer query level.
*/
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 11ef4765d86..96692544634 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -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);
@@ -1062,6 +1038,52 @@ build_tlist_index(List *tlist)
}
/*
+ * 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
*
* If a match is found, return a copy of the given Var with suitably
@@ -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
*****************************************************************************/
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 2fe78473048..ad128605dcc 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.40 2006/08/10 02:36:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.41 2006/08/12 02:52:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -372,6 +372,10 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
ResolveNew((Node *) parse->targetList,
varno, 0, rte,
subtlist, CMD_SELECT, 0);
+ parse->returningList = (List *)
+ ResolveNew((Node *) parse->returningList,
+ varno, 0, rte,
+ subtlist, CMD_SELECT, 0);
resolvenew_in_jointree((Node *) parse->jointree, varno,
rte, subtlist);
Assert(parse->setOperations == NULL);
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 0e06d0e8881..c4bbd9d2eec 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -9,13 +9,14 @@
* relation in the correct order. For both UPDATE and DELETE queries,
* we need a junk targetlist entry holding the CTID attribute --- the
* executor relies on this to find the tuple to be replaced/deleted.
+ * We may also need junk tlist entries for Vars used in the RETURNING list.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.82 2006/04/30 18:30:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.83 2006/08/12 02:52:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +28,8 @@
#include "nodes/makefuncs.h"
#include "optimizer/prep.h"
#include "optimizer/subselect.h"
+#include "optimizer/tlist.h"
+#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
@@ -151,6 +154,40 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
}
}
+ /*
+ * If the query has a RETURNING list, add resjunk entries for any Vars
+ * used in RETURNING that belong to other relations. We need to do this
+ * to make these Vars available for the RETURNING calculation. Vars
+ * that belong to the result rel don't need to be added, because they
+ * will be made to refer to the actual heap tuple.
+ */
+ if (parse->returningList && list_length(parse->rtable) > 1)
+ {
+ List *vars;
+ ListCell *l;
+
+ vars = pull_var_clause((Node *) parse->returningList, false);
+ foreach(l, vars)
+ {
+ Var *var = (Var *) lfirst(l);
+ TargetEntry *tle;
+
+ if (var->varno == result_relation)
+ continue; /* don't need it */
+
+ if (tlist_member((Node *) var, tlist))
+ continue; /* already got it */
+
+ tle = makeTargetEntry((Expr *) var,
+ list_length(tlist) + 1,
+ NULL,
+ true);
+
+ tlist = lappend(tlist, tle);
+ }
+ list_free(vars);
+ }
+
return tlist;
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 73fe60bd24e..04f346d4625 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.217 2006/08/04 14:09:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.218 2006/08/12 02:52:05 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -3351,6 +3351,8 @@ query_tree_walker(Query *query,
if (walker((Node *) query->targetList, context))
return true;
+ if (walker((Node *) query->returningList, context))
+ return true;
if (walker((Node *) query->jointree, context))
return true;
if (walker(query->setOperations, context))
@@ -3913,6 +3915,7 @@ query_tree_mutator(Query *query,
}
MUTATE(query->targetList, query->targetList, List *);
+ MUTATE(query->returningList, query->returningList, List *);
MUTATE(query->jointree, query->jointree, FromExpr *);
MUTATE(query->setOperations, query->setOperations, Node *);
MUTATE(query->havingQual, query->havingQual, Node *);