Skip to content

Commit 68fa28f

Browse files
committed
Postpone extParam/allParam calculations until the very end of planning.
Until now we computed these Param ID sets at the end of subquery_planner, but that approach depends on subquery_planner returning a concrete Plan tree. We would like to switch over to returning one or more Paths for a subquery, and in that representation the necessary details aren't fully fleshed out (not to mention that we don't really want to do this work for Paths that end up getting discarded). Hence, refactor so that we can compute the param ID sets at the end of planning, just before set_plan_references is run. The main change necessary to make this work is that we need to capture the set of outer-level Param IDs available to the current query level before exiting subquery_planner, since the outer levels' plan_params lists are transient. (That's not going to pose a problem for returning Paths, since all the work involved in producing that data is part of expression preprocessing, which will continue to happen before Paths are produced.) On the plus side, this change gets rid of several existing kluges. Eventually I'd like to get rid of SS_finalize_plan altogether in favor of doing this work during set_plan_references, but that will require some complex rejiggering because SS_finalize_plan needs to visit subplans and initplans before the main plan. So leave that idea for another day.
1 parent 4901b2f commit 68fa28f

File tree

10 files changed

+293
-158
lines changed

10 files changed

+293
-158
lines changed

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
17991799
WRITE_NODE_FIELD(glob);
18001800
WRITE_UINT_FIELD(query_level);
18011801
WRITE_NODE_FIELD(plan_params);
1802+
WRITE_BITMAPSET_FIELD(outer_params);
18021803
WRITE_BITMAPSET_FIELD(all_baserels);
18031804
WRITE_BITMAPSET_FIELD(nullable_baserels);
18041805
WRITE_NODE_FIELD(join_rel_list);

src/backend/optimizer/plan/createplan.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4473,11 +4473,7 @@ make_material(Plan *lefttree)
44734473
* materialize_finished_plan: stick a Material node atop a completed plan
44744474
*
44754475
* There are a couple of places where we want to attach a Material node
4476-
* after completion of subquery_planner(). This currently requires hackery.
4477-
* Since subquery_planner has already run SS_finalize_plan on the subplan
4478-
* tree, we have to kluge up parameter lists for the Material node.
4479-
* Possibly this could be fixed by postponing SS_finalize_plan processing
4480-
* until setrefs.c is run?
4476+
* after completion of subquery_planner(), without any MaterialPath path.
44814477
*/
44824478
Plan *
44834479
materialize_finished_plan(Plan *subplan)
@@ -4498,10 +4494,6 @@ materialize_finished_plan(Plan *subplan)
44984494
matplan->plan_rows = subplan->plan_rows;
44994495
matplan->plan_width = subplan->plan_width;
45004496

4501-
/* parameter kluge --- see comments above */
4502-
matplan->extParam = bms_copy(subplan->extParam);
4503-
matplan->allParam = bms_copy(subplan->allParam);
4504-
45054497
return matplan;
45064498
}
45074499

src/backend/optimizer/plan/planagg.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,23 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
416416
* WHERE col IS NOT NULL AND existing-quals
417417
* ORDER BY col ASC/DESC
418418
* LIMIT 1)
419+
*
420+
* We cheat a bit here by building what is effectively a subplan query
421+
* level without taking the trouble to increment varlevelsup of outer
422+
* references. Therefore we don't increment the subroot's query_level nor
423+
* repoint its parent_root to the parent level. We can get away with that
424+
* because the plan will be an initplan and therefore cannot need any
425+
* parameters from the parent level. But see hackery in make_agg_subplan;
426+
* we might someday need to do this the hard way.
419427
*----------
420428
*/
421429
subroot = (PlannerInfo *) palloc(sizeof(PlannerInfo));
422430
memcpy(subroot, root, sizeof(PlannerInfo));
423431
subroot->parse = parse = (Query *) copyObject(root->parse);
424-
/* make sure subroot planning won't change root->init_plans contents */
425-
subroot->init_plans = list_copy(root->init_plans);
432+
/* reset subplan-related stuff */
433+
subroot->plan_params = NIL;
434+
subroot->outer_params = NULL;
435+
subroot->init_plans = NIL;
426436
/* There shouldn't be any OJ or LATERAL info to translate, as yet */
427437
Assert(subroot->join_info_list == NIL);
428438
Assert(subroot->lateral_info_list == NIL);
@@ -577,24 +587,31 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *mminfo)
577587
subparse->limitCount,
578588
0, 1);
579589

590+
/*
591+
* We have to do some of the same cleanup that subquery_planner() would
592+
* do, namely cope with params and initplans used within this plan tree.
593+
*
594+
* This is a little bit messy because although we initially created the
595+
* subroot by cloning the outer root, it really is a subplan and needs to
596+
* consider initplans belonging to the outer root as providing available
597+
* parameters. So temporarily change its parent_root pointer.
598+
* (Fortunately, SS_identify_outer_params doesn't care whether the depth
599+
* of parent_root nesting matches query_level.)
600+
*/
601+
subroot->parent_root = root;
602+
SS_identify_outer_params(subroot);
603+
subroot->parent_root = root->parent_root;
604+
605+
SS_attach_initplans(subroot, plan);
606+
580607
/*
581608
* Convert the plan into an InitPlan, and make a Param for its result.
582609
*/
583610
mminfo->param =
584-
SS_make_initplan_from_plan(subroot, plan,
611+
SS_make_initplan_from_plan(root, subroot, plan,
585612
exprType((Node *) mminfo->target),
586613
-1,
587614
exprCollation((Node *) mminfo->target));
588-
589-
/*
590-
* Make sure the initplan gets into the outer PlannerInfo, along with any
591-
* other initplans generated by the sub-planning run. We had to include
592-
* the outer PlannerInfo's pre-existing initplans into the inner one's
593-
* init_plans list earlier, so make sure we don't put back any duplicate
594-
* entries.
595-
*/
596-
root->init_plans = list_concat_unique_ptr(root->init_plans,
597-
subroot->init_plans);
598615
}
599616

600617
/*

src/backend/optimizer/plan/planner.c

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,25 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
239239
top_plan = materialize_finished_plan(top_plan);
240240
}
241241

242+
/*
243+
* If any Params were generated, run through the plan tree and compute
244+
* each plan node's extParam/allParam sets. Ideally we'd merge this into
245+
* set_plan_references' tree traversal, but for now it has to be separate
246+
* because we need to visit subplans before not after main plan.
247+
*/
248+
if (glob->nParamExec > 0)
249+
{
250+
Assert(list_length(glob->subplans) == list_length(glob->subroots));
251+
forboth(lp, glob->subplans, lr, glob->subroots)
252+
{
253+
Plan *subplan = (Plan *) lfirst(lp);
254+
PlannerInfo *subroot = (PlannerInfo *) lfirst(lr);
255+
256+
SS_finalize_plan(subroot, subplan);
257+
}
258+
SS_finalize_plan(root, top_plan);
259+
}
260+
242261
/* final cleanup of the plan */
243262
Assert(glob->finalrtable == NIL);
244263
Assert(glob->finalrowmarks == NIL);
@@ -312,7 +331,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
312331
bool hasRecursion, double tuple_fraction,
313332
PlannerInfo **subroot)
314333
{
315-
int num_old_subplans = list_length(glob->subplans);
316334
PlannerInfo *root;
317335
Plan *plan;
318336
List *newWithCheckOptions;
@@ -327,6 +345,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
327345
root->query_level = parent_root ? parent_root->query_level + 1 : 1;
328346
root->parent_root = parent_root;
329347
root->plan_params = NIL;
348+
root->outer_params = NULL;
330349
root->planner_cxt = CurrentMemoryContext;
331350
root->init_plans = NIL;
332351
root->cte_plan_ids = NIL;
@@ -656,13 +675,17 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
656675
}
657676

658677
/*
659-
* If any subplans were generated, or if there are any parameters to worry
660-
* about, build initPlan list and extParam/allParam sets for plan nodes,
661-
* and attach the initPlans to the top plan node.
678+
* Capture the set of outer-level param IDs we have access to, for use in
679+
* extParam/allParam calculations later.
680+
*/
681+
SS_identify_outer_params(root);
682+
683+
/*
684+
* If any initPlans were created in this query level, attach them to the
685+
* topmost plan node for the level, and increment that node's cost to
686+
* account for them.
662687
*/
663-
if (list_length(glob->subplans) != num_old_subplans ||
664-
root->glob->nParamExec > 0)
665-
SS_finalize_plan(root, plan, true);
688+
SS_attach_initplans(root, plan);
666689

667690
/* Return internal info if caller wants it */
668691
if (subroot)

0 commit comments

Comments
 (0)