1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Don't scan partitioned tables.

Partitioned tables do not contain any data; only their unpartitioned
descendents need to be scanned.  However, the partitioned tables still
need to be locked, even though they're not scanned.  To make that
work, Append and MergeAppend relations now need to carry a list of
(unscanned) partitioned relations that must be locked, and InitPlan
must lock all partitioned result relations.

Aside from the obvious advantage of avoiding some work at execution
time, this has two other advantages.  First, it may improve the
planner's decision-making in some cases since the empty relation
might throw things off.  Second, it paves the way to getting rid of
the storage for partitioned tables altogether.

Amit Langote, reviewed by me.

Discussion: http://postgr.es/m/6837c359-45c4-8044-34d1-736756335a15@lab.ntt.co.jp
This commit is contained in:
Robert Haas
2017-03-21 09:48:04 -04:00
parent d5286aa905
commit d3cc37f1d8
27 changed files with 537 additions and 164 deletions

View File

@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
List *all_child_pathkeys);
List *all_child_pathkeys,
List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@ -346,6 +347,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
{
/*
* A partitioned table without leaf partitions is marked
* as a dummy rel.
*/
set_dummy_rel_pathlist(rel);
}
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@ -1259,6 +1268,16 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
List *partitioned_rels = NIL;
RangeTblEntry *rte;
rte = planner_rt_fetch(rel->relid, root);
if (rte->relkind == RELKIND_PARTITIONED_TABLE)
{
partitioned_rels = get_partitioned_child_rels(root, rel->relid);
/* The root partitioned table is included as a child rel */
Assert(list_length(partitioned_rels) >= 1);
}
/*
* For every non-dummy child, remember the cheapest path. Also, identify
@ -1359,7 +1378,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@ -1386,7 +1406,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
parallel_workers);
parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@ -1396,7 +1416,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
all_child_pathkeys);
all_child_pathkeys,
partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@ -1438,7 +1459,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
create_append_path(rel, subpaths, required_outer, 0));
create_append_path(rel, subpaths, required_outer, 0,
partitioned_rels));
}
}
@ -1468,7 +1490,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
List *all_child_pathkeys)
List *all_child_pathkeys,
List *partitioned_rels)
{
ListCell *lcp;
@ -1532,13 +1555,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
NULL));
NULL,
partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
NULL));
NULL,
partitioned_rels));
}
}
@ -1671,7 +1696,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()

View File

@ -1217,7 +1217,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);

View File

@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
static Append *make_append(List *appendplans, List *tlist);
static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
Index nominalRelation,
Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
plan = make_append(subplans, tlist);
plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@ -2314,6 +2315,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@ -5161,7 +5163,7 @@ make_foreignscan(List *qptlist,
}
static Append *
make_append(List *appendplans, List *tlist)
make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@ -5170,6 +5172,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@ -6282,7 +6285,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
Index nominalRelation,
Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@ -6308,6 +6311,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;

View File

@ -212,6 +212,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
glob->nonleafResultRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->nParamExec = 0;
@ -380,6 +381,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
Assert(glob->nonleafResultRelations == NIL);
top_plan = set_plan_references(root, top_plan);
/* ... and the subplans (both regular subplans and initplans) */
Assert(list_length(glob->subplans) == list_length(glob->subroots));
@ -405,6 +407,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->planTree = top_plan;
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
result->nonleafResultRelations = glob->nonleafResultRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
@ -474,6 +477,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->multiexpr_params = NIL;
root->eq_classes = NIL;
root->append_rel_list = NIL;
root->pcinfo_list = NIL;
root->rowMarks = NIL;
memset(root->upper_rels, 0, sizeof(root->upper_rels));
memset(root->upper_targets, 0, sizeof(root->upper_targets));
@ -1007,6 +1011,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@ -1064,6 +1070,18 @@ inheritance_planner(PlannerInfo *root)
}
}
/*
* If the parent RTE is a partitioned table, we should use that as the
* nominal relation, because the RTEs added for partitioned tables
* (including the root parent) as child members of the inheritance set
* do not appear anywhere else in the plan. The situation is exactly
* the opposite in the case of non-partitioned inheritance parent as
* described below.
*/
parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
nominalRelation = parentRTindex;
/*
* And now we can get on with generating a plan for each child table.
*/
@ -1071,7 +1089,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@ -1216,15 +1233,25 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
* We'll use the first child relation (even if it's excluded) as the
* nominal target relation of the ModifyTable node. Because of the
* way expand_inherited_rtentry works, this should always be the RTE
* representing the parent table in its role as a simple member of the
* inheritance set. (It would be logically cleaner to use the
* inheritance parent RTE as the nominal target; but since that RTE
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
* Set the nomimal target relation of the ModifyTable node if not
* already done. We use the inheritance parent RTE as the nominal
* target relation if it's a partitioned table (see just above this
* loop). In the non-partitioned parent case, we'll use the first
* child relation (even if it's excluded) as the nominal target
* relation. Because of the way expand_inherited_rtentry works, the
* latter should be the RTE representing the parent table in its role
* as a simple member of the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
* parent RTE as the nominal relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
* would give rise to confusing use of multiple aliases in EXPLAIN
* output for what the user will think is the "same" table. OTOH,
* it's not a problem in the partitioned inheritance case, because
* the duplicate child RTE added for the parent does not appear
* anywhere else in the plan tree.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@ -1298,6 +1325,13 @@ inheritance_planner(PlannerInfo *root)
Assert(!parse->onConflict);
}
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
partitioned_rels = get_partitioned_child_rels(root, parentRTindex);
/* The root partitioned table is included as a child rel */
Assert(list_length(partitioned_rels) >= 1);
}
/* Result path must go into outer query's FINAL upperrel */
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@ -1351,6 +1385,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
partitioned_rels,
resultRelations,
subpaths,
subroots,
@ -2046,6 +2081,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@ -3348,7 +3384,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
0);
0,
NIL);
path->pathtarget = target;
}
else
@ -5470,3 +5507,33 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
}
/*
* get_partitioned_child_rels
* Returns a list of the RT indexes of the partitioned child relations
* with rti as the root parent RT index.
*
* Note: Only call this function on RTEs known to be partitioned tables.
*/
List *
get_partitioned_child_rels(PlannerInfo *root, Index rti)
{
List *result = NIL;
ListCell *l;
foreach(l, root->pcinfo_list)
{
PartitionedChildRelInfo *pc = lfirst(l);
if (pc->parent_relid == rti)
{
result = pc->child_rels;
break;
}
}
/* The root partitioned table is included as a child rel */
Assert(list_length(result) >= 1);
return result;
}

View File

@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
foreach(l, splan->partitioned_rels)
{
lfirst_int(l) += rtoffset;
}
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@ -863,6 +867,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
list_copy(splan->resultRelations));
/*
* If the main target relation is a partitioned table, the
* following list contains the RT indexes of partitioned child
* relations, which are not included in the above list.
*/
root->glob->nonleafResultRelations =
list_concat(root->glob->nonleafResultRelations,
list_copy(splan->partitioned_rels));
}
break;
case T_Append:
@ -875,6 +888,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
foreach(l, splan->partitioned_rels)
{
lfirst_int(l) += rtoffset;
}
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@ -893,6 +910,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
foreach(l, splan->partitioned_rels)
{
lfirst_int(l) += rtoffset;
}
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,

View File

@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@ -1364,6 +1364,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
bool need_append;
PartitionedChildRelInfo *pcinfo;
List *partitioned_child_rels = NIL;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@ -1435,6 +1438,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
need_append = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@ -1483,36 +1487,46 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
childRTindex = list_length(parse->rtable);
/*
* Build an AppendRelInfo for this parent and child.
* Build an AppendRelInfo for this parent and child, unless the child
* is a partitioned table.
*/
appinfo = makeNode(AppendRelInfo);
appinfo->parent_relid = rti;
appinfo->child_relid = childRTindex;
appinfo->parent_reltype = oldrelation->rd_rel->reltype;
appinfo->child_reltype = newrelation->rd_rel->reltype;
make_inh_translation_list(oldrelation, newrelation, childRTindex,
&appinfo->translated_vars);
appinfo->parent_reloid = parentOID;
appinfos = lappend(appinfos, appinfo);
/*
* Translate the column permissions bitmaps to the child's attnums (we
* have to build the translated_vars list before we can do this). But
* if this is the parent table, leave copyObject's result alone.
*
* Note: we need to do this even though the executor won't run any
* permissions checks on the child RTE. The insertedCols/updatedCols
* bitmaps may be examined for trigger-firing purposes.
*/
if (childOID != parentOID)
if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
{
childrte->selectedCols = translate_col_privs(rte->selectedCols,
need_append = true;
appinfo = makeNode(AppendRelInfo);
appinfo->parent_relid = rti;
appinfo->child_relid = childRTindex;
appinfo->parent_reltype = oldrelation->rd_rel->reltype;
appinfo->child_reltype = newrelation->rd_rel->reltype;
make_inh_translation_list(oldrelation, newrelation, childRTindex,
&appinfo->translated_vars);
appinfo->parent_reloid = parentOID;
appinfos = lappend(appinfos, appinfo);
/*
* Translate the column permissions bitmaps to the child's attnums
* (we have to build the translated_vars list before we can do
* this). But if this is the parent table, leave copyObject's
* result alone.
*
* Note: we need to do this even though the executor won't run any
* permissions checks on the child RTE. The
* insertedCols/updatedCols bitmaps may be examined for
* trigger-firing purposes.
*/
if (childOID != parentOID)
{
childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
childrte->insertedCols = translate_col_privs(rte->insertedCols,
childrte->insertedCols = translate_col_privs(rte->insertedCols,
appinfo->translated_vars);
childrte->updatedCols = translate_col_privs(rte->updatedCols,
childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
}
}
else
partitioned_child_rels = lappend_int(partitioned_child_rels,
childRTindex);
/*
* Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
@ -1529,7 +1543,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = oldrc->strength;
newrc->waitPolicy = oldrc->waitPolicy;
newrc->isParent = false;
/*
* We mark RowMarks for partitioned child tables as parent RowMarks
* so that the executor ignores them (except their existence means
* that the child tables be locked using appropriate mode).
*/
newrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
/* Include child's rowmark type in parent's allMarkTypes */
oldrc->allMarkTypes |= newrc->allMarkTypes;
@ -1545,18 +1565,37 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
* PlanRowMark node.
* If all the children were temp tables or a partitioned parent did not
* have any leaf partitions, pretend it's a non-inheritance situation; we
* don't need Append node in that case. The duplicate RTE we added for
* the parent table is harmless, so we don't bother to get rid of it;
* ditto for the useless PlanRowMark node.
*/
if (list_length(appinfos) < 2)
if (!need_append)
{
/* Clear flag before returning */
rte->inh = false;
return;
}
/*
* We keep a list of objects in root, each of which maps a partitioned
* parent RT index to the list of RT indexes of its partitioned child
* tables. When creating an Append or a ModifyTable path for the parent,
* we copy the child RT index list verbatim to the path so that it could
* be carried over to the executor so that the latter could identify
* the partitioned child tables.
*/
if (partitioned_child_rels != NIL)
{
pcinfo = makeNode(PartitionedChildRelInfo);
Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
pcinfo->parent_relid = rti;
pcinfo->child_rels = partitioned_child_rels;
root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
}
/* Otherwise, OK to add to root->append_rel_list */
root->append_rel_list = list_concat(root->append_rel_list, appinfos);
}

View File

@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
int parallel_workers)
int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
Relids required_outer)
Relids required_outer,
List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
Index nominalRelation,
Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;