summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/subselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r--src/backend/optimizer/plan/subselect.c84
1 files changed, 65 insertions, 19 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 250ba8edcb8..7a9fe88fec3 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1016,8 +1016,7 @@ SS_process_ctes(PlannerInfo *root)
/*
* CTE scans are not considered for parallelism (cf
- * set_rel_consider_parallel), and even if they were, initPlans aren't
- * parallel-safe.
+ * set_rel_consider_parallel).
*/
splan->parallel_safe = false;
splan->setParam = NIL;
@@ -2120,8 +2119,8 @@ SS_identify_outer_params(PlannerInfo *root)
* If any initPlans have been created in the current query level, they will
* get attached to the Plan tree created from whichever Path we select from
* the given rel. Increment all that rel's Paths' costs to account for them,
- * and make sure the paths get marked as parallel-unsafe, since we can't
- * currently transmit initPlans to parallel workers.
+ * and if any of the initPlans are parallel-unsafe, mark all the rel's Paths
+ * parallel-unsafe as well.
*
* This is separate from SS_attach_initplans because we might conditionally
* create more initPlans during create_plan(), depending on which Path we
@@ -2132,6 +2131,7 @@ void
SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
{
Cost initplan_cost;
+ bool unsafe_initplans;
ListCell *lc;
/* Nothing to do if no initPlans */
@@ -2140,17 +2140,10 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
/*
* Compute the cost increment just once, since it will be the same for all
- * Paths. We assume each initPlan gets run once during top plan startup.
- * This is a conservative overestimate, since in fact an initPlan might be
- * executed later than plan startup, or even not at all.
+ * Paths. Also check for parallel-unsafe initPlans.
*/
- initplan_cost = 0;
- foreach(lc, root->init_plans)
- {
- SubPlan *initsubplan = (SubPlan *) lfirst(lc);
-
- initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
- }
+ SS_compute_initplan_cost(root->init_plans,
+ &initplan_cost, &unsafe_initplans);
/*
* Now adjust the costs and parallel_safe flags.
@@ -2161,20 +2154,72 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
path->startup_cost += initplan_cost;
path->total_cost += initplan_cost;
- path->parallel_safe = false;
+ if (unsafe_initplans)
+ path->parallel_safe = false;
}
/*
- * Forget about any partial paths and clear consider_parallel, too;
- * they're not usable if we attached an initPlan.
+ * Adjust partial paths' costs too, or forget them entirely if we must
+ * consider the rel parallel-unsafe.
*/
- final_rel->partial_pathlist = NIL;
- final_rel->consider_parallel = false;
+ if (unsafe_initplans)
+ {
+ final_rel->partial_pathlist = NIL;
+ final_rel->consider_parallel = false;
+ }
+ else
+ {
+ foreach(lc, final_rel->partial_pathlist)
+ {
+ Path *path = (Path *) lfirst(lc);
+
+ path->startup_cost += initplan_cost;
+ path->total_cost += initplan_cost;
+ }
+ }
/* We needn't do set_cheapest() here, caller will do it */
}
/*
+ * SS_compute_initplan_cost - count up the cost delta for some initplans
+ *
+ * The total cost returned in *initplan_cost_p should be added to both the
+ * startup and total costs of the plan node the initplans get attached to.
+ * We also report whether any of the initplans are not parallel-safe.
+ *
+ * The primary user of this is SS_charge_for_initplans, but it's also
+ * used in adjusting costs when we move initplans to another plan node.
+ */
+void
+SS_compute_initplan_cost(List *init_plans,
+ Cost *initplan_cost_p,
+ bool *unsafe_initplans_p)
+{
+ Cost initplan_cost;
+ bool unsafe_initplans;
+ ListCell *lc;
+
+ /*
+ * We assume each initPlan gets run once during top plan startup. This is
+ * a conservative overestimate, since in fact an initPlan might be
+ * executed later than plan startup, or even not at all.
+ */
+ initplan_cost = 0;
+ unsafe_initplans = false;
+ foreach(lc, init_plans)
+ {
+ SubPlan *initsubplan = lfirst_node(SubPlan, lc);
+
+ initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
+ if (!initsubplan->parallel_safe)
+ unsafe_initplans = true;
+ }
+ *initplan_cost_p = initplan_cost;
+ *unsafe_initplans_p = unsafe_initplans;
+}
+
+/*
* SS_attach_initplans - attach initplans to topmost plan node
*
* Attach any initplans created in the current query level to the specified
@@ -2990,6 +3035,7 @@ SS_make_initplan_from_plan(PlannerInfo *root,
node->plan_id, prm->paramid);
get_first_col_type(plan, &node->firstColType, &node->firstColTypmod,
&node->firstColCollation);
+ node->parallel_safe = plan->parallel_safe;
node->setParam = list_make1_int(prm->paramid);
root->init_plans = lappend(root->init_plans, node);