diff options
Diffstat (limited to 'src/backend/optimizer/plan/setrefs.c')
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 264 |
1 files changed, 172 insertions, 92 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 0213a376705..4204ca4025d 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -94,12 +94,19 @@ static Plan *set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset); static bool trivial_subqueryscan(SubqueryScan *plan); +static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child); static void set_foreignscan_references(PlannerInfo *root, ForeignScan *fscan, int rtoffset); static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset); +static Plan *set_append_references(PlannerInfo *root, + Append *aplan, + int rtoffset); +static Plan *set_mergeappend_references(PlannerInfo *root, + MergeAppend *mplan, + int rtoffset); static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset); static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); @@ -181,19 +188,22 @@ static List *set_returning_clause_references(PlannerInfo *root, * 8. We assign every plan node in the tree a unique ID. * * We also perform one final optimization step, which is to delete - * SubqueryScan plan nodes that aren't doing anything useful (ie, have - * no qual and a no-op targetlist). The reason for doing this last is that + * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing + * anything useful. The reason for doing this last is that * it can't readily be done before set_plan_references, because it would - * break set_upper_references: the Vars in the subquery's top tlist - * wouldn't match up with the Vars in the outer plan tree. The SubqueryScan + * break set_upper_references: the Vars in the child plan's top tlist + * wouldn't match up with the Vars in the outer plan tree. A SubqueryScan * serves a necessary function as a buffer between outer query and subquery * variable numbering ... but after we've flattened the rangetable this is * no longer a problem, since then there's only one rtindex namespace. + * Likewise, Append and MergeAppend buffer between the parent and child vars + * of an appendrel, but we don't need to worry about that once we've done + * set_plan_references. * * set_plan_references recursively traverses the whole plan tree. * * The return value is normally the same Plan node passed in, but can be - * different when the passed-in Plan is a SubqueryScan we decide isn't needed. + * different when the passed-in Plan is a node we decide isn't needed. * * The flattened rangetable entries are appended to root->glob->finalrtable. * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the @@ -897,71 +907,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } break; case T_Append: - { - Append *splan = (Append *) plan; - - /* - * Append, like Sort et al, doesn't actually evaluate its - * targetlist or check quals. - */ - set_dummy_tlist_references(plan, rtoffset); - Assert(splan->plan.qual == NIL); - foreach(l, splan->appendplans) - { - lfirst(l) = set_plan_refs(root, - (Plan *) lfirst(l), - rtoffset); - } - if (splan->part_prune_info) - { - foreach(l, splan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - } - } - } - } - break; + /* Needs special treatment, see comments below */ + return set_append_references(root, + (Append *) plan, + rtoffset); case T_MergeAppend: - { - MergeAppend *splan = (MergeAppend *) plan; - - /* - * MergeAppend, like Sort et al, doesn't actually evaluate its - * targetlist or check quals. - */ - set_dummy_tlist_references(plan, rtoffset); - Assert(splan->plan.qual == NIL); - foreach(l, splan->mergeplans) - { - lfirst(l) = set_plan_refs(root, - (Plan *) lfirst(l), + /* Needs special treatment, see comments below */ + return set_mergeappend_references(root, + (MergeAppend *) plan, rtoffset); - } - if (splan->part_prune_info) - { - foreach(l, splan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - } - } - } - } - break; case T_RecursiveUnion: /* This doesn't evaluate targetlist or check quals either */ set_dummy_tlist_references(plan, rtoffset); @@ -1086,30 +1040,7 @@ set_subqueryscan_references(PlannerInfo *root, /* * We can omit the SubqueryScan node and just pull up the subplan. */ - ListCell *lp, - *lc; - - result = plan->subplan; - - /* We have to be sure we don't lose any initplans */ - result->initPlan = list_concat(plan->scan.plan.initPlan, - result->initPlan); - - /* - * We also have to transfer the SubqueryScan's result-column names - * into the subplan, else columns sent to client will be improperly - * labeled if this is the topmost plan level. Copy the "source - * column" information too. - */ - forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist) - { - TargetEntry *ptle = (TargetEntry *) lfirst(lp); - TargetEntry *ctle = (TargetEntry *) lfirst(lc); - - ctle->resname = ptle->resname; - ctle->resorigtbl = ptle->resorigtbl; - ctle->resorigcol = ptle->resorigcol; - } + result = clean_up_removed_plan_level((Plan *) plan, plan->subplan); } else { @@ -1191,6 +1122,30 @@ trivial_subqueryscan(SubqueryScan *plan) } /* + * clean_up_removed_plan_level + * Do necessary cleanup when we strip out a SubqueryScan, Append, etc + * + * We are dropping the "parent" plan in favor of returning just its "child". + * A few small tweaks are needed. + */ +static Plan * +clean_up_removed_plan_level(Plan *parent, Plan *child) +{ + /* We have to be sure we don't lose any initplans */ + child->initPlan = list_concat(parent->initPlan, + child->initPlan); + + /* + * We also have to transfer the parent's column labeling info into the + * child, else columns sent to client will be improperly labeled if this + * is the topmost plan level. resjunk and so on may be important too. + */ + apply_tlist_labeling(child->targetlist, parent->targetlist); + + return child; +} + +/* * set_foreignscan_references * Do set_plan_references processing on a ForeignScan */ @@ -1341,6 +1296,131 @@ set_customscan_references(PlannerInfo *root, } /* + * set_append_references + * Do set_plan_references processing on an Append + * + * We try to strip out the Append entirely; if we can't, we have + * to do the normal processing on it. + */ +static Plan * +set_append_references(PlannerInfo *root, + Append *aplan, + int rtoffset) +{ + ListCell *l; + + /* + * Append, like Sort et al, doesn't actually evaluate its targetlist or + * check quals. If it's got exactly one child plan, then it's not doing + * anything useful at all, and we can strip it out. + */ + Assert(aplan->plan.qual == NIL); + + /* First, we gotta recurse on the children */ + foreach(l, aplan->appendplans) + { + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); + } + + /* Now, if there's just one, forget the Append and return that child */ + if (list_length(aplan->appendplans) == 1) + return clean_up_removed_plan_level((Plan *) aplan, + (Plan *) linitial(aplan->appendplans)); + + /* + * Otherwise, clean up the Append as needed. It's okay to do this after + * recursing to the children, because set_dummy_tlist_references doesn't + * look at those. + */ + set_dummy_tlist_references((Plan *) aplan, rtoffset); + + if (aplan->part_prune_info) + { + foreach(l, aplan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } + + /* We don't need to recurse to lefttree or righttree ... */ + Assert(aplan->plan.lefttree == NULL); + Assert(aplan->plan.righttree == NULL); + + return (Plan *) aplan; +} + +/* + * set_mergeappend_references + * Do set_plan_references processing on a MergeAppend + * + * We try to strip out the MergeAppend entirely; if we can't, we have + * to do the normal processing on it. + */ +static Plan * +set_mergeappend_references(PlannerInfo *root, + MergeAppend *mplan, + int rtoffset) +{ + ListCell *l; + + /* + * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist + * or check quals. If it's got exactly one child plan, then it's not + * doing anything useful at all, and we can strip it out. + */ + Assert(mplan->plan.qual == NIL); + + /* First, we gotta recurse on the children */ + foreach(l, mplan->mergeplans) + { + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); + } + + /* Now, if there's just one, forget the MergeAppend and return that child */ + if (list_length(mplan->mergeplans) == 1) + return clean_up_removed_plan_level((Plan *) mplan, + (Plan *) linitial(mplan->mergeplans)); + + /* + * Otherwise, clean up the MergeAppend as needed. It's okay to do this + * after recursing to the children, because set_dummy_tlist_references + * doesn't look at those. + */ + set_dummy_tlist_references((Plan *) mplan, rtoffset); + + if (mplan->part_prune_info) + { + foreach(l, mplan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } + + /* We don't need to recurse to lefttree or righttree ... */ + Assert(mplan->plan.lefttree == NULL); + Assert(mplan->plan.righttree == NULL); + + return (Plan *) mplan; +} + + +/* * copyVar * Copy a Var node. * |