diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index cc42946..e1517ed 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -157,7 +157,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->rtable = estate->es_range_table; pstmt->resultRelations = NIL; pstmt->utilityStmt = NULL; - pstmt->subplans = NIL; + pstmt->subplans = estate->es_plannedstmt->subplans; pstmt->rewindPlanIDs = NULL; pstmt->rowMarks = NIL; pstmt->relationOids = NIL; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6955298..5e52d9d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -115,6 +115,7 @@ CopyPlanFields(const Plan *from, Plan *newnode) COPY_SCALAR_FIELD(plan_rows); COPY_SCALAR_FIELD(plan_width); COPY_SCALAR_FIELD(parallel_aware); + COPY_SCALAR_FIELD(parallel_safe); COPY_SCALAR_FIELD(plan_node_id); COPY_NODE_FIELD(targetlist); COPY_NODE_FIELD(qual); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 9fe9873..381034f 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -272,6 +272,7 @@ _outPlanInfo(StringInfo str, const Plan *node) WRITE_FLOAT_FIELD(plan_rows, "%.0f"); WRITE_INT_FIELD(plan_width); WRITE_BOOL_FIELD(parallel_aware); + WRITE_BOOL_FIELD(parallel_safe); WRITE_INT_FIELD(plan_node_id); WRITE_NODE_FIELD(targetlist); WRITE_NODE_FIELD(qual); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 63f6336..418bd6b 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1440,6 +1440,7 @@ ReadCommonPlan(Plan *local_node) READ_FLOAT_FIELD(plan_rows); READ_INT_FIELD(plan_width); READ_BOOL_FIELD(parallel_aware); + READ_BOOL_FIELD(parallel_safe); READ_INT_FIELD(plan_node_id); READ_NODE_FIELD(targetlist); READ_NODE_FIELD(qual); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index ad49674..a4a78ce 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1854,6 +1854,7 @@ create_minmaxagg_plan(PlannerInfo *root, MinMaxAggPath *best_path) plan->plan_rows = 1; plan->plan_width = mminfo->path->pathtarget->width; plan->parallel_aware = false; + plan->parallel_safe = mminfo->path->parallel_safe; /* Convert the plan into an InitPlan in the outer query. */ SS_make_initplan_from_plan(root, subroot, plan, mminfo->param); @@ -2697,6 +2698,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ plan->parallel_aware = false; + plan->parallel_safe = apath->path.parallel_safe; *qual = subquals; *indexqual = subindexquals; *indexECs = subindexECs; @@ -2760,6 +2762,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ plan->parallel_aware = false; + plan->parallel_safe = opath->path.parallel_safe; } /* @@ -2804,6 +2807,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ plan->parallel_aware = false; + plan->parallel_safe = ipath->path.parallel_safe; *qual = get_actual_clauses(ipath->indexclauses); *indexqual = get_actual_clauses(ipath->indexquals); foreach(l, ipath->indexinfo->indpred) @@ -4592,6 +4596,7 @@ copy_generic_path_info(Plan *dest, Path *src) dest->plan_rows = src->rows; dest->plan_width = src->pathtarget->width; dest->parallel_aware = src->parallel_aware; + dest->parallel_safe = src->parallel_safe; } /* @@ -4607,6 +4612,7 @@ copy_plan_costsize(Plan *dest, Plan *src) dest->plan_width = src->plan_width; /* Assume the inserted node is not parallel-aware. */ dest->parallel_aware = false; + dest->parallel_safe = src->parallel_safe; } /* @@ -4636,6 +4642,7 @@ label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples) plan->plan.plan_rows = lefttree->plan_rows; plan->plan.plan_width = lefttree->plan_width; plan->plan.parallel_aware = false; + plan->plan.parallel_safe = sort_path.parallel_safe; } @@ -5647,6 +5654,7 @@ materialize_finished_plan(Plan *subplan) matplan->plan_rows = subplan->plan_rows; matplan->plan_width = subplan->plan_width; matplan->parallel_aware = false; + matplan->parallel_safe = matpath.parallel_safe; return matplan; } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 41dde50..28775b5 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -366,6 +366,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) gather->plan.plan_rows = top_plan->plan_rows; gather->plan.plan_width = top_plan->plan_width; gather->plan.parallel_aware = false; + gather->plan.parallel_safe = false; /* use parallel mode for parallel plans. */ root->glob->parallelModeNeeded = true; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 9af29dd..eabdc15 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -91,6 +91,7 @@ typedef struct typedef struct { + PlannerInfo *root; char max_hazard; /* worst proparallel hazard found so far */ char max_interesting; /* worst proparallel hazard of interest */ } max_parallel_hazard_context; @@ -1132,6 +1133,7 @@ max_parallel_hazard(Query *parse) { max_parallel_hazard_context context; + context.root = NULL; context.max_hazard = PROPARALLEL_SAFE; context.max_interesting = PROPARALLEL_UNSAFE; (void) max_parallel_hazard_walker((Node *) parse, &context); @@ -1160,6 +1162,7 @@ is_parallel_safe(PlannerInfo *root, Node *node) root->glob->nParamExec == 0) return true; /* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */ + context.root = root; context.max_hazard = PROPARALLEL_SAFE; context.max_interesting = PROPARALLEL_RESTRICTED; return !max_parallel_hazard_walker(node, &context); @@ -1240,19 +1243,37 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) } /* - * Since we don't have the ability to push subplans down to workers at - * present, we treat subplan references as parallel-restricted. We need - * not worry about examining their contents; if they are unsafe, we would - * have found that out while examining the whole tree before reduction of - * sublinks to subplans. (Really we should not see SubLink during a - * max_interesting == restricted scan, but if we do, return true.) + * We can push the subplans only if they don't contain any parallel-aware + * node as we don't support multi-level parallelism (parallel workers + * invoking another set of parallel workers). */ - else if (IsA(node, SubLink) || - IsA(node, SubPlan) || - IsA(node, AlternativeSubPlan)) + else if (IsA(node, SubPlan)) { - if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) - return true; + Plan *plan; + + Assert(context->root); + + plan = planner_subplan_get_plan(context->root, (SubPlan *) node); + return !plan->parallel_safe; + } + else if (IsA(node, AlternativeSubPlan)) + { + AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; + ListCell *lc; + + Assert(context->root); + + foreach(lc, asplan->subplans) + { + SubPlan *splan = (SubPlan *) lfirst(lc); + Plan *plan; + + Assert(IsA(splan, SubPlan)); + + plan = planner_subplan_get_plan(context->root, splan); + if (!plan->parallel_safe) + return true; + } } /* diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index e2fbc7d..8ffb70d 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -112,6 +112,7 @@ typedef struct Plan * information needed for parallel query */ bool parallel_aware; /* engage parallel-aware logic? */ + bool parallel_safe; /* OK to use as part of parallel plan? */ /* * Common structural data for all Plan types.