diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/plan/planagg.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 39 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 137 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 39 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 5 |
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 *); |