diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 73 |
1 files changed, 55 insertions, 18 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index a09b4b5b479..a3cc27464c1 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -48,10 +48,12 @@ #include "storage/dsm_impl.h" #include "utils/rel.h" #include "utils/selfuncs.h" +#include "utils/syscache.h" -/* GUC parameter */ +/* GUC parameters */ double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION; +int force_parallel_mode = FORCE_PARALLEL_OFF; /* Hook for plugins to get control in planner() */ planner_hook_type planner_hook = NULL; @@ -230,25 +232,31 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) !has_parallel_hazard((Node *) parse, true); /* - * glob->parallelModeOK should tell us whether it's necessary to impose - * the parallel mode restrictions, but we don't actually want to impose - * them unless we choose a parallel plan, so that people who mislabel - * their functions but don't use parallelism anyway aren't harmed. - * However, it's useful for testing purposes to be able to force the - * restrictions to be imposed whenever a parallel plan is actually chosen - * or not. + * glob->parallelModeNeeded should tell us whether it's necessary to + * impose the parallel mode restrictions, but we don't actually want to + * impose them unless we choose a parallel plan, so that people who + * mislabel their functions but don't use parallelism anyway aren't + * harmed. But when force_parallel_mode is set, we enable the restrictions + * whenever possible for testing purposes. * - * (It's been suggested that we should always impose these restrictions - * whenever glob->parallelModeOK is true, so that it's easier to notice - * incorrectly-labeled functions sooner. That might be the right thing to - * do, but for now I've taken this approach. We could also control this - * with a GUC.) + * glob->wholePlanParallelSafe should tell us whether it's OK to stick a + * Gather node on top of the entire plan. However, it only needs to be + * accurate when force_parallel_mode is 'on' or 'regress', so we don't + * bother doing the work otherwise. The value we set here is just a + * preliminary guess; it may get changed from true to false later, but + * not visca versa. */ -#ifdef FORCE_PARALLEL_MODE - glob->parallelModeNeeded = glob->parallelModeOK; -#else - glob->parallelModeNeeded = false; -#endif + if (force_parallel_mode == FORCE_PARALLEL_OFF || !glob->parallelModeOK) + { + glob->parallelModeNeeded = false; + glob->wholePlanParallelSafe = false; /* either false or don't care */ + } + else + { + glob->parallelModeNeeded = true; + glob->wholePlanParallelSafe = + !has_parallel_hazard((Node *) parse, false); + } /* Determine what fraction of the plan is likely to be scanned */ if (cursorOptions & CURSOR_OPT_FAST_PLAN) @@ -293,6 +301,35 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) } /* + * At present, we don't copy subplans to workers. The presence of a + * subplan in one part of the plan doesn't preclude the use of parallelism + * in some other part of the plan, but it does preclude the possibility of + * regarding the entire plan parallel-safe. + */ + if (glob->subplans != NULL) + glob->wholePlanParallelSafe = false; + + /* + * Optionally add a Gather node for testing purposes, provided this is + * actually a safe thing to do. + */ + if (glob->wholePlanParallelSafe && + force_parallel_mode != FORCE_PARALLEL_OFF) + { + Gather *gather = makeNode(Gather); + + gather->plan.targetlist = top_plan->targetlist; + gather->plan.qual = NIL; + gather->plan.lefttree = top_plan; + gather->plan.righttree = NULL; + gather->num_workers = 1; + gather->single_copy = true; + gather->invisible = (force_parallel_mode == FORCE_PARALLEL_REGRESS); + root->glob->parallelModeNeeded = true; + top_plan = &gather->plan; + } + + /* * If any Params were generated, run through the plan tree and compute * each plan node's extParam/allParam sets. Ideally we'd merge this into * set_plan_references' tree traversal, but for now it has to be separate |