diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 07b925e74c5..dad35e56f58 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1500,6 +1500,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, PathTarget *grouping_target; PathTarget *scanjoin_target; bool have_grouping; + bool scanjoin_target_parallel_safe = false; WindowFuncLists *wflists = NULL; List *activeWindows = NIL; List *rollup_lists = NIL; @@ -1730,7 +1731,16 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, scanjoin_target = grouping_target; /* - * Forcibly apply that target to all the Paths for the scan/join rel. + * Check whether scan/join target is parallel safe ... unless there + * are no partial paths, in which case we don't care. + */ + if (current_rel->partial_pathlist && + !has_parallel_hazard((Node *) scanjoin_target->exprs, false)) + scanjoin_target_parallel_safe = true; + + /* + * Forcibly apply scan/join target to all the Paths for the scan/join + * rel. * * In principle we should re-run set_cheapest() here to identify the * cheapest path, but it seems unlikely that adding the same tlist @@ -1746,7 +1756,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, Assert(subpath->param_info == NULL); path = apply_projection_to_path(root, current_rel, - subpath, scanjoin_target); + subpath, scanjoin_target, + scanjoin_target_parallel_safe); /* If we had to add a Result, path is different from subpath */ if (path != subpath) { @@ -1759,6 +1770,70 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, } /* + * Upper planning steps which make use of the top scan/join rel's + * partial pathlist will expect partial paths for that rel to produce + * the same output as complete paths ... and we just changed the + * output for the complete paths, so we'll need to do the same thing + * for partial paths. + */ + if (scanjoin_target_parallel_safe) + { + /* + * Apply the scan/join target to each partial path. Otherwise, + * anything that attempts to use the partial paths for further + * upper planning may go wrong. + */ + foreach(lc, current_rel->partial_pathlist) + { + Path *subpath = (Path *) lfirst(lc); + Path *newpath; + + /* + * We can't use apply_projection_to_path() here, because there + * could already be pointers to these paths, and therefore we + * cannot modify them in place. Instead, we must use + * create_projection_path(). The good news is this won't + * actually insert a Result node into the final plan unless + * it's needed, but the bad news is that it will charge for + * the node whether it's needed or not. Therefore, if the + * target list is already what we need it to be, just leave + * this partial path alone. + */ + if (equal(scanjoin_target->exprs, subpath->pathtarget->exprs)) + continue; + + Assert(subpath->param_info == NULL); + newpath = (Path *) create_projection_path(root, + current_rel, + subpath, + scanjoin_target); + if (is_projection_capable_path(subpath)) + { + /* + * Since the target lists differ, a projection path is + * essential, but it will disappear at plan creation time + * because the subpath is projection-capable. So avoid + * charging anything for the disappearing node. + */ + newpath->startup_cost = subpath->startup_cost; + newpath->total_cost = subpath->total_cost; + } + + lfirst(lc) = newpath; + } + } + else + { + /* + * In the unfortunate event that scanjoin_target is not + * parallel-safe, we can't apply it to the partial paths; in that + * case, we'll need to forget about the partial paths, which + * aren't valid input for upper planning steps. + */ + current_rel->partial_pathlist = NIL; + } + + /* * Save the various upper-rel PathTargets we just computed into * root->upper_targets[]. The core code doesn't use this, but it * provides a convenient place for extensions to get at the info. For @@ -4153,7 +4228,7 @@ create_ordered_paths(PlannerInfo *root, /* Add projection step if needed */ if (path->pathtarget != target) path = apply_projection_to_path(root, ordered_rel, - path, target); + path, target, false); add_path(ordered_rel, path); } |