diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 6d0b3dbce95695e14fc2fe180874a66ceb6c1549..fe8ea7e0a4a7f1ed1974d1548987ae311b57bc7f 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -41,6 +41,7 @@ #include "parser/parse_oper.h" #include "parser/parsetree.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" #include "utils/syscache.h" @@ -741,19 +742,52 @@ inheritance_planner(PlannerInfo *root) List *rowMarks; List *tlist; PlannerInfo subroot; + MemoryContext childcxt; ListCell *l; + /* + * Memory management here is a bit messy, because the planning process can + * scribble on both the query parsetree and the rangetable. We need to + * ensure that each call of grouping_planner gets an un-scribbled-on copy + * to start with, so we start by copying the given query tree each time + * (as a byproduct of adjust_appendrel_attrs). However, we also want to + * make sure that the modified rangetable ultimately gets propagated back + * to the master copy, to pick up any changes of the Query structures + * inside subquery RTEs. We do that by copying back the rangetable from + * the first successful child planning step. (We are effectively assuming + * that sub-Queries will get planned identically each time, or at least + * that the impacts on their rangetables will be the same each time.) + * + * Another consideration is that when there are a lot of child tables, we + * can eat a lot of memory this way. To fix that, we create a child + * memory context that can be reset between steps to recover memory, at + * the cost of having to copy the completed plan trees out to the parent + * context. + */ + childcxt = AllocSetContextCreate(CurrentMemoryContext, + "Inheritance child planning context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + foreach(l, root->append_rel_list) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); Plan *subplan; + MemoryContext oldcxt; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) continue; /* - * Generate modified query with this rel as target. + * Discard any cruft generated in previous loop iterations. + */ + MemoryContextReset(childcxt); + oldcxt = MemoryContextSwitchTo(childcxt); + + /* + * Generate modified query (in childcxt) with this rel as target. */ memcpy(&subroot, root, sizeof(PlannerInfo)); subroot.parse = (Query *) @@ -767,9 +801,11 @@ inheritance_planner(PlannerInfo *root) /* and we haven't created PlaceHolderInfos, either */ Assert(subroot.placeholder_list == NIL); - /* Generate plan */ + /* Generate plan (also in childcxt) */ subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ ); + MemoryContextSwitchTo(oldcxt); + /* * If this child rel was excluded by constraint exclusion, exclude it * from the plan. @@ -777,14 +813,20 @@ inheritance_planner(PlannerInfo *root) if (is_dummy_plan(subplan)) continue; - /* Save rtable from first rel for use below */ + /* + * Be sure to copy what we need out of the child context. + */ + subplan = copyObject(subplan); + + /* Save rtable from first child to install in parent after the loop */ if (subplans == NIL) - rtable = subroot.parse->rtable; + rtable = copyObject(subroot.parse->rtable); subplans = lappend(subplans, subplan); /* Make sure any initplans from this rel get into the outer list */ - root->init_plans = list_concat(root->init_plans, subroot.init_plans); + root->init_plans = list_concat(root->init_plans, + copyObject(subroot.init_plans)); /* Build target-relations list for the executor */ resultRelations = lappend_int(resultRelations, appinfo->child_relid); @@ -794,14 +836,18 @@ inheritance_planner(PlannerInfo *root) { List *rlist; + rlist = copyObject(subroot.parse->returningList); rlist = set_returning_clause_references(root->glob, - subroot.parse->returningList, + rlist, subplan, appinfo->child_relid); returningLists = lappend(returningLists, rlist); } } + /* Done with child context */ + MemoryContextDelete(childcxt); + root->resultRelations = resultRelations; /* Mark result as unordered (probably unnecessary) */ @@ -824,15 +870,7 @@ inheritance_planner(PlannerInfo *root) } /* - * Planning might have modified the rangetable, due to changes of the - * Query structures inside subquery RTEs. We have to ensure that this - * gets propagated back to the master copy. But can't do this until we - * are done planning, because all the calls to grouping_planner need - * virgin sub-Queries to work from. (We are effectively assuming that - * sub-Queries will get planned identically each time, or at least that - * the impacts on their rangetables will be the same each time.) - * - * XXX should clean this up someday + * Install modified rangetable from first child into parent parsetree. */ parse->rtable = rtable;