diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 0355b52ed4..bff05267fb 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1725,35 +1725,35 @@ static Node * fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan, double num_exec) { - SubPlan *subplan1; - SubPlan *subplan2; - Cost cost1; - Cost cost2; + SubPlan *bestplan = NULL; + Cost bestcost; ListCell *lc; - /* Currently there will always be exactly 2 alternatives */ - Assert(list_length(asplan->subplans) == 2); - subplan1 = (SubPlan *) linitial(asplan->subplans); - subplan2 = (SubPlan *) lsecond(asplan->subplans); + Assert(list_length(asplan->subplans) > 0); - /* Choose the one that's cheaper assuming num_exec executions */ - cost1 = subplan1->startup_cost + num_exec * subplan1->per_call_cost; - cost2 = subplan2->startup_cost + num_exec * subplan2->per_call_cost; - - if (cost1 < cost2) - { - /* Delete subplan2 and return subplan1 */ - lc = list_nth_cell(root->glob->subplans, subplan2->plan_id - 1); - lfirst(lc) = NULL; - return (Node *) subplan1; - } - else + foreach(lc, asplan->subplans) { - /* Delete subplan1 and return subplan2 */ - lc = list_nth_cell(root->glob->subplans, subplan1->plan_id - 1); - lfirst(lc) = NULL; - return (Node *) subplan2; + SubPlan *curplan = (SubPlan *) lfirst(lc); + Cost curcost; + + curcost = curplan->startup_cost + num_exec * curplan->per_call_cost; + if (bestplan == NULL) + { + bestplan = curplan; + bestcost = curcost; + } + else if (curcost < bestcost) + { + /* NULLify discarded subplan */ + lc = list_nth_cell(root->glob->subplans, bestplan->plan_id - 1); + lfirst(lc) = NULL; + + bestplan = curplan; + bestcost = curcost; + } } + + return (Node *) bestplan; } /* diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index fd65ee8f9c..21ccb4f026 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -739,10 +739,7 @@ typedef struct SubPlan * This is used only transiently during planning: by the time the plan * reaches the executor, all AlternativeSubPlan nodes have been removed. * - * The subplans are given as a List so that the node definition need not - * change if there's ever more than two alternatives. For the moment, - * though, there are always exactly two; and the first one is the fast-start - * plan. + * The subplans List must contain at least one subplan. */ typedef struct AlternativeSubPlan {