aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c73
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