From 8b6e7b09772ef20a81844567681fc8e4ac586240 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 5 Apr 2026 04:00:15 +0300 Subject: [PATCH v19 3/6] Introduce AppendBase/AppendBaseState base types for Append/MergeAppend Introduce common base types AppendBase (plan node) and AppendBaseState (executor state) to unify the fields shared between Append/MergeAppend and AppendState/MergeAppendState. AppendBase holds the subplan list, appendrel identifiers, and partition pruning index. AppendBaseState holds the subplan state array, asynchronous execution infrastructure, and partition pruning state. Append and MergeAppend now embed AppendBase as their first field (ab), while AppendState and MergeAppendState both embed AppendBaseState as their first field (as). This follows the same C struct inheritance pattern used by Scan/ScanState and Join/JoinState throughout the codebase. The name "AppendBase" was chosen because just "Append" is already taken. Discussion: https://postgr.es/m/59be194c5a409fb9fc9f2031581b8a44%40postgrespro.ru Author: Matheus Alcantara Co-authored-by: Alexander Korotkov Reviewed-by: Alexander Pyhalov Reviewed-by: Alena Rybakina --- contrib/pg_overexplain/pg_overexplain.c | 8 +- contrib/pg_plan_advice/pgpa_scan.c | 4 +- contrib/pg_plan_advice/pgpa_walker.c | 8 +- contrib/postgres_fdw/postgres_fdw.c | 12 +- src/backend/commands/explain.c | 52 +---- src/backend/executor/execAmi.c | 2 +- src/backend/executor/execCurrent.c | 4 +- src/backend/executor/execProcnode.c | 8 +- src/backend/executor/nodeAppend.c | 284 ++++++++++++------------ src/backend/executor/nodeMergeAppend.c | 82 +++---- src/backend/nodes/nodeFuncs.c | 9 +- src/backend/optimizer/plan/createplan.c | 46 ++-- src/backend/optimizer/plan/setrefs.c | 173 ++++----------- src/backend/optimizer/plan/subselect.c | 4 +- src/backend/utils/adt/ruleutils.c | 8 +- src/include/nodes/execnodes.h | 65 ++++-- src/include/nodes/plannodes.h | 66 +++--- src/tools/pgindent/typedefs.list | 2 + 18 files changed, 370 insertions(+), 467 deletions(-) diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c index a93a4dcfed6..1f48faa475f 100644 --- a/contrib/pg_overexplain/pg_overexplain.c +++ b/contrib/pg_overexplain/pg_overexplain.c @@ -234,18 +234,18 @@ overexplain_per_node_hook(PlanState *planstate, List *ancestors, break; case T_Append: overexplain_bitmapset("Append RTIs", - ((Append *) plan)->apprelids, + ((Append *) plan)->ab.apprelids, es); overexplain_bitmapset_list("Child Append RTIs", - ((Append *) plan)->child_append_relid_sets, + ((Append *) plan)->ab.child_append_relid_sets, es); break; case T_MergeAppend: overexplain_bitmapset("Append RTIs", - ((MergeAppend *) plan)->apprelids, + ((MergeAppend *) plan)->ab.apprelids, es); overexplain_bitmapset_list("Child Append RTIs", - ((MergeAppend *) plan)->child_append_relid_sets, + ((MergeAppend *) plan)->ab.child_append_relid_sets, es); break; case T_Result: diff --git a/contrib/pg_plan_advice/pgpa_scan.c b/contrib/pg_plan_advice/pgpa_scan.c index 4da77936216..f8fc3d0bb63 100644 --- a/contrib/pg_plan_advice/pgpa_scan.c +++ b/contrib/pg_plan_advice/pgpa_scan.c @@ -164,7 +164,7 @@ pgpa_build_scan(pgpa_plan_walker_context *walker, Plan *plan, /* Be sure to account for pulled-up scans. */ child_append_relid_sets = - ((Append *) plan)->child_append_relid_sets; + ((Append *) plan)->ab.child_append_relid_sets; break; case T_MergeAppend: /* Same logic here as for Append, above. */ @@ -176,7 +176,7 @@ pgpa_build_scan(pgpa_plan_walker_context *walker, Plan *plan, /* Be sure to account for pulled-up scans. */ child_append_relid_sets = - ((MergeAppend *) plan)->child_append_relid_sets; + ((MergeAppend *) plan)->ab.child_append_relid_sets; break; default: strategy = PGPA_SCAN_ORDINARY; diff --git a/contrib/pg_plan_advice/pgpa_walker.c b/contrib/pg_plan_advice/pgpa_walker.c index e49361ae266..f4bec204fad 100644 --- a/contrib/pg_plan_advice/pgpa_walker.c +++ b/contrib/pg_plan_advice/pgpa_walker.c @@ -441,14 +441,14 @@ pgpa_walk_recursively(pgpa_plan_walker_context *walker, Plan *plan, { Append *aplan = (Append *) plan; - extraplans = aplan->appendplans; + extraplans = aplan->ab.subplans; } break; case T_MergeAppend: { MergeAppend *maplan = (MergeAppend *) plan; - extraplans = maplan->mergeplans; + extraplans = maplan->ab.subplans; } break; case T_BitmapAnd: @@ -571,9 +571,9 @@ pgpa_relids(Plan *plan) else if (IsA(plan, ForeignScan)) return ((ForeignScan *) plan)->fs_relids; else if (IsA(plan, Append)) - return ((Append *) plan)->apprelids; + return ((Append *) plan)->ab.apprelids; else if (IsA(plan, MergeAppend)) - return ((MergeAppend *) plan)->apprelids; + return ((MergeAppend *) plan)->ab.apprelids; return NULL; } diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 6fa45773c30..117804cff55 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -2628,8 +2628,8 @@ find_modifytable_subplan(PlannerInfo *root, { Append *appendplan = (Append *) subplan; - if (subplan_index < list_length(appendplan->appendplans)) - subplan = (Plan *) list_nth(appendplan->appendplans, subplan_index); + if (subplan_index < list_length(appendplan->ab.subplans)) + subplan = (Plan *) list_nth(appendplan->ab.subplans, subplan_index); } else if (IsA(subplan, Result) && outerPlan(subplan) != NULL && @@ -2637,8 +2637,8 @@ find_modifytable_subplan(PlannerInfo *root, { Append *appendplan = (Append *) outerPlan(subplan); - if (subplan_index < list_length(appendplan->appendplans)) - subplan = (Plan *) list_nth(appendplan->appendplans, subplan_index); + if (subplan_index < list_length(appendplan->ab.subplans)) + subplan = (Plan *) list_nth(appendplan->ab.subplans, subplan_index); } /* Now, have we got a ForeignScan on the desired rel? */ @@ -8163,7 +8163,7 @@ postgresForeignAsyncConfigureWait(AsyncRequest *areq) PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state; AsyncRequest *pendingAreq = fsstate->conn_state->pendingAreq; AppendState *requestor = (AppendState *) areq->requestor; - WaitEventSet *set = requestor->as_eventset; + WaitEventSet *set = requestor->as.eventset; /* This should not be called unless callback_pending */ Assert(areq->callback_pending); @@ -8205,7 +8205,7 @@ postgresForeignAsyncConfigureWait(AsyncRequest *areq) * below, because we might otherwise end up with no configured events * other than the postmaster death event. */ - if (!bms_is_empty(requestor->as_needrequest)) + if (!bms_is_empty(requestor->as.needrequest)) return; if (GetNumRegisteredWaitEvents(set) > 1) return; diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index a40d03d35f3..6afedfd243c 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1230,12 +1230,9 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used) linitial_int(((ModifyTable *) plan)->resultRelations)); break; case T_Append: - *rels_used = bms_add_members(*rels_used, - ((Append *) plan)->apprelids); - break; case T_MergeAppend: *rels_used = bms_add_members(*rels_used, - ((MergeAppend *) plan)->apprelids); + ((AppendBase *) plan)->apprelids); break; case T_Result: *rels_used = bms_add_members(*rels_used, @@ -1269,34 +1266,17 @@ plan_is_disabled(Plan *plan) * Handle special nodes first. Children of BitmapOrs and BitmapAnds can't * be disabled, so no need to handle those specifically. */ - if (IsA(plan, Append)) - { - ListCell *lc; - Append *aplan = (Append *) plan; - - /* - * Sum the Append childrens' disabled_nodes. This purposefully - * includes any run-time pruned children. Ignoring those could give - * us the incorrect number of disabled nodes. - */ - foreach(lc, aplan->appendplans) - { - Plan *subplan = lfirst(lc); - - child_disabled_nodes += subplan->disabled_nodes; - } - } - else if (IsA(plan, MergeAppend)) + if (IsA(plan, Append) || IsA(plan, MergeAppend)) { ListCell *lc; - MergeAppend *maplan = (MergeAppend *) plan; + AppendBase *abplan = (AppendBase *) plan; /* - * Sum the MergeAppend childrens' disabled_nodes. This purposefully - * includes any run-time pruned children. Ignoring those could give - * us the incorrect number of disabled nodes. + * Sum the Append/MergeAppend childrens' disabled_nodes. This + * purposefully includes any run-time pruned children. Ignoring + * those could give us the incorrect number of disabled nodes. */ - foreach(lc, maplan->mergeplans) + foreach(lc, abplan->subplans) { Plan *subplan = lfirst(lc); @@ -2347,13 +2327,9 @@ ExplainNode(PlanState *planstate, List *ancestors, switch (nodeTag(plan)) { case T_Append: - ExplainMissingMembers(((AppendState *) planstate)->as_nplans, - list_length(((Append *) plan)->appendplans), - es); - break; case T_MergeAppend: - ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans, - list_length(((MergeAppend *) plan)->mergeplans), + ExplainMissingMembers(((AppendBaseState *) planstate)->nplans, + list_length(((AppendBase *) plan)->subplans), es); break; default: @@ -2397,13 +2373,9 @@ ExplainNode(PlanState *planstate, List *ancestors, switch (nodeTag(plan)) { case T_Append: - ExplainMemberNodes(((AppendState *) planstate)->appendplans, - ((AppendState *) planstate)->as_nplans, - ancestors, es); - break; case T_MergeAppend: - ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans, - ((MergeAppendState *) planstate)->ms_nplans, + ExplainMemberNodes(((AppendBaseState *) planstate)->plans, + ((AppendBaseState *) planstate)->nplans, ancestors, es); break; case T_BitmapAnd: @@ -2617,7 +2589,7 @@ static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, ExplainState *es) { - MergeAppend *plan = (MergeAppend *) mstate->ps.plan; + MergeAppend *plan = (MergeAppend *) mstate->as.ps.plan; show_sort_group_keys((PlanState *) mstate, "Sort Key", plan->numCols, 0, plan->sortColIdx, diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 37fe03fdc37..2d8e621208f 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -538,7 +538,7 @@ ExecSupportsBackwardScan(Plan *node) if (((Append *) node)->nasyncplans > 0) return false; - foreach(l, ((Append *) node)->appendplans) + foreach(l, ((Append *) node)->ab.subplans) { if (!ExecSupportsBackwardScan((Plan *) lfirst(l))) return false; diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index 99f2b2d0c6f..37f5c7fd2c5 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -375,9 +375,9 @@ search_plan_tree(PlanState *node, Oid table_oid, AppendState *astate = (AppendState *) node; int i; - for (i = 0; i < astate->as_nplans; i++) + for (i = 0; i < astate->as.nplans; i++) { - ScanState *elem = search_plan_tree(astate->appendplans[i], + ScanState *elem = search_plan_tree(astate->as.plans[i], table_oid, pending_rescan); diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 7c4c66e323f..fa1c69bf89f 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -891,8 +891,8 @@ ExecSetTupleBound(int64 tuples_needed, PlanState *child_node) AppendState *aState = (AppendState *) child_node; int i; - for (i = 0; i < aState->as_nplans; i++) - ExecSetTupleBound(tuples_needed, aState->appendplans[i]); + for (i = 0; i < aState->as.nplans; i++) + ExecSetTupleBound(tuples_needed, aState->as.plans[i]); } else if (IsA(child_node, MergeAppendState)) { @@ -904,8 +904,8 @@ ExecSetTupleBound(int64 tuples_needed, PlanState *child_node) MergeAppendState *maState = (MergeAppendState *) child_node; int i; - for (i = 0; i < maState->ms_nplans; i++) - ExecSetTupleBound(tuples_needed, maState->mergeplans[i]); + for (i = 0; i < maState->as.nplans; i++) + ExecSetTupleBound(tuples_needed, maState->as.plans[i]); } else if (IsA(child_node, ResultState)) { diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 6a5a14cd576..438d960eb87 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -128,9 +128,9 @@ ExecInitAppend(Append *node, EState *estate, int eflags) /* * create new AppendState for our append node */ - appendstate->ps.plan = (Plan *) node; - appendstate->ps.state = estate; - appendstate->ps.ExecProcNode = ExecAppend; + appendstate->as.ps.plan = (Plan *) node; + appendstate->as.ps.state = estate; + appendstate->as.ps.ExecProcNode = ExecAppend; /* Let choose_next_subplan_* function handle setting the first subplan */ appendstate->as_whichplan = INVALID_SUBPLAN_INDEX; @@ -138,7 +138,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendstate->as_begun = false; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_index >= 0) + if (node->ab.part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -147,12 +147,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags) * subplans to initialize (validsubplans) by taking into account the * result of performing initial pruning if any. */ - prunestate = ExecInitPartitionExecPruning(&appendstate->ps, - list_length(node->appendplans), - node->part_prune_index, - node->apprelids, + prunestate = ExecInitPartitionExecPruning(&appendstate->as.ps, + list_length(node->ab.subplans), + node->ab.part_prune_index, + node->ab.apprelids, &validsubplans); - appendstate->as_prune_state = prunestate; + appendstate->as.prune_state = prunestate; nplans = bms_num_members(validsubplans); /* @@ -162,23 +162,23 @@ ExecInitAppend(Append *node, EState *estate, int eflags) */ if (!prunestate->do_exec_prune && nplans > 0) { - appendstate->as_valid_subplans = bms_add_range(NULL, 0, nplans - 1); - appendstate->as_valid_subplans_identified = true; + appendstate->as.valid_subplans = bms_add_range(NULL, 0, nplans - 1); + appendstate->as.valid_subplans_identified = true; } } else { - nplans = list_length(node->appendplans); + nplans = list_length(node->ab.subplans); /* * When run-time partition pruning is not enabled we can just mark all * subplans as valid; they must also all be initialized. */ Assert(nplans > 0); - appendstate->as_valid_subplans = validsubplans = + appendstate->as.valid_subplans = validsubplans = bms_add_range(NULL, 0, nplans - 1); - appendstate->as_valid_subplans_identified = true; - appendstate->as_prune_state = NULL; + appendstate->as.valid_subplans_identified = true; + appendstate->as.prune_state = NULL; } appendplanstates = (PlanState **) palloc(nplans * @@ -197,7 +197,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) i = -1; while ((i = bms_next_member(validsubplans, i)) >= 0) { - Plan *initNode = (Plan *) list_nth(node->appendplans, i); + Plan *initNode = (Plan *) list_nth(node->ab.subplans, i); /* * Record async subplans. When executing EvalPlanQual, we treat them @@ -220,8 +220,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags) } appendstate->as_first_partial_plan = firstvalid; - appendstate->appendplans = appendplanstates; - appendstate->as_nplans = nplans; + appendstate->as.plans = appendplanstates; + appendstate->as.nplans = nplans; /* * Initialize Append's result tuple type and slot. If the child plans all @@ -235,30 +235,30 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendops = ExecGetCommonSlotOps(appendplanstates, j); if (appendops != NULL) { - ExecInitResultTupleSlotTL(&appendstate->ps, appendops); + ExecInitResultTupleSlotTL(&appendstate->as.ps, appendops); } else { - ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual); + ExecInitResultTupleSlotTL(&appendstate->as.ps, &TTSOpsVirtual); /* show that the output slot type is not fixed */ - appendstate->ps.resultopsset = true; - appendstate->ps.resultopsfixed = false; + appendstate->as.ps.resultopsset = true; + appendstate->as.ps.resultopsfixed = false; } /* Initialize async state */ - appendstate->as_asyncplans = asyncplans; - appendstate->as_nasyncplans = nasyncplans; - appendstate->as_asyncrequests = NULL; - appendstate->as_asyncresults = NULL; + appendstate->as.asyncplans = asyncplans; + appendstate->as.nasyncplans = nasyncplans; + appendstate->as.asyncrequests = NULL; + appendstate->as.asyncresults = NULL; appendstate->as_nasyncresults = 0; appendstate->as_nasyncremain = 0; - appendstate->as_needrequest = NULL; - appendstate->as_eventset = NULL; - appendstate->as_valid_asyncplans = NULL; + appendstate->as.needrequest = NULL; + appendstate->as.eventset = NULL; + appendstate->as.valid_asyncplans = NULL; if (nasyncplans > 0) { - appendstate->as_asyncrequests = (AsyncRequest **) + appendstate->as.asyncrequests = (AsyncRequest **) palloc0(nplans * sizeof(AsyncRequest *)); i = -1; @@ -274,13 +274,13 @@ ExecInitAppend(Append *node, EState *estate, int eflags) areq->request_complete = false; areq->result = NULL; - appendstate->as_asyncrequests[i] = areq; + appendstate->as.asyncrequests[i] = areq; } - appendstate->as_asyncresults = (TupleTableSlot **) + appendstate->as.asyncresults = (TupleTableSlot **) palloc0(nasyncplans * sizeof(TupleTableSlot *)); - if (appendstate->as_valid_subplans_identified) + if (appendstate->as.valid_subplans_identified) classify_matching_subplans(appendstate); } @@ -288,7 +288,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) * Miscellaneous initialization */ - appendstate->ps.ps_ProjInfo = NULL; + appendstate->as.ps.ps_ProjInfo = NULL; /* For parallel query, this will be overridden later. */ appendstate->choose_next_subplan = choose_next_subplan_locally; @@ -318,11 +318,11 @@ ExecAppend(PlanState *pstate) Assert(!node->as_syncdone); /* Nothing to do if there are no subplans */ - if (node->as_nplans == 0) - return ExecClearTuple(node->ps.ps_ResultTupleSlot); + if (node->as.nplans == 0) + return ExecClearTuple(node->as.ps.ps_ResultTupleSlot); /* If there are any async subplans, begin executing them. */ - if (node->as_nasyncplans > 0) + if (node->as.nasyncplans > 0) ExecAppendAsyncBegin(node); /* @@ -330,11 +330,11 @@ ExecAppend(PlanState *pstate) * proceeding. */ if (!node->choose_next_subplan(node) && node->as_nasyncremain == 0) - return ExecClearTuple(node->ps.ps_ResultTupleSlot); + return ExecClearTuple(node->as.ps.ps_ResultTupleSlot); Assert(node->as_syncdone || (node->as_whichplan >= 0 && - node->as_whichplan < node->as_nplans)); + node->as_whichplan < node->as.nplans)); /* And we're initialized. */ node->as_begun = true; @@ -349,19 +349,19 @@ ExecAppend(PlanState *pstate) /* * try to get a tuple from an async subplan if any */ - if (node->as_syncdone || !bms_is_empty(node->as_needrequest)) + if (node->as_syncdone || !bms_is_empty(node->as.needrequest)) { if (ExecAppendAsyncGetNext(node, &result)) return result; Assert(!node->as_syncdone); - Assert(bms_is_empty(node->as_needrequest)); + Assert(bms_is_empty(node->as.needrequest)); } /* * figure out which sync subplan we are currently processing */ - Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as_nplans); - subnode = node->appendplans[node->as_whichplan]; + Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as.nplans); + subnode = node->as.plans[node->as_whichplan]; /* * get a tuple from the subplan @@ -388,7 +388,7 @@ ExecAppend(PlanState *pstate) /* choose new sync subplan; if no sync/async subplans, we're done */ if (!node->choose_next_subplan(node) && node->as_nasyncremain == 0) - return ExecClearTuple(node->ps.ps_ResultTupleSlot); + return ExecClearTuple(node->as.ps.ps_ResultTupleSlot); } } @@ -410,8 +410,8 @@ ExecEndAppend(AppendState *node) /* * get information from the node */ - appendplans = node->appendplans; - nplans = node->as_nplans; + appendplans = node->as.plans; + nplans = node->as.nplans; /* * shut down each of the subscans @@ -423,7 +423,7 @@ ExecEndAppend(AppendState *node) void ExecReScanAppend(AppendState *node) { - int nasyncplans = node->as_nasyncplans; + int nasyncplans = node->as.nasyncplans; int i; /* @@ -431,27 +431,27 @@ ExecReScanAppend(AppendState *node) * we'd better unset the valid subplans so that they are reselected for * the new parameter values. */ - if (node->as_prune_state && - bms_overlap(node->ps.chgParam, - node->as_prune_state->execparamids)) + if (node->as.prune_state && + bms_overlap(node->as.ps.chgParam, + node->as.prune_state->execparamids)) { - node->as_valid_subplans_identified = false; - bms_free(node->as_valid_subplans); - node->as_valid_subplans = NULL; - bms_free(node->as_valid_asyncplans); - node->as_valid_asyncplans = NULL; + node->as.valid_subplans_identified = false; + bms_free(node->as.valid_subplans); + node->as.valid_subplans = NULL; + bms_free(node->as.valid_asyncplans); + node->as.valid_asyncplans = NULL; } - for (i = 0; i < node->as_nplans; i++) + for (i = 0; i < node->as.nplans; i++) { - PlanState *subnode = node->appendplans[i]; + PlanState *subnode = node->as.plans[i]; /* * ExecReScan doesn't know about my subplans, so I have to do * changed-parameter signaling myself. */ - if (node->ps.chgParam != NULL) - UpdateChangedParamSet(subnode, node->ps.chgParam); + if (node->as.ps.chgParam != NULL) + UpdateChangedParamSet(subnode, node->as.ps.chgParam); /* * If chgParam of subnode is not null then plan will be re-scanned by @@ -465,9 +465,9 @@ ExecReScanAppend(AppendState *node) if (nasyncplans > 0) { i = -1; - while ((i = bms_next_member(node->as_asyncplans, i)) >= 0) + while ((i = bms_next_member(node->as.asyncplans, i)) >= 0) { - AsyncRequest *areq = node->as_asyncrequests[i]; + AsyncRequest *areq = node->as.asyncrequests[i]; /* * Leave a request that is still marked as pending a callback @@ -490,8 +490,8 @@ ExecReScanAppend(AppendState *node) node->as_nasyncresults = 0; node->as_nasyncremain = 0; - bms_free(node->as_needrequest); - node->as_needrequest = NULL; + bms_free(node->as.needrequest); + node->as.needrequest = NULL; } /* Let choose_next_subplan_* function handle setting the first subplan */ @@ -518,7 +518,7 @@ ExecAppendEstimate(AppendState *node, { node->pstate_len = add_size(offsetof(ParallelAppendState, pa_finished), - sizeof(bool) * node->as_nplans); + sizeof(bool) * node->as.nplans); shm_toc_estimate_chunk(&pcxt->estimator, node->pstate_len); shm_toc_estimate_keys(&pcxt->estimator, 1); @@ -540,7 +540,7 @@ ExecAppendInitializeDSM(AppendState *node, pstate = shm_toc_allocate(pcxt->toc, node->pstate_len); memset(pstate, 0, node->pstate_len); LWLockInitialize(&pstate->pa_lock, LWTRANCHE_PARALLEL_APPEND); - shm_toc_insert(pcxt->toc, node->ps.plan->plan_node_id, pstate); + shm_toc_insert(pcxt->toc, node->as.ps.plan->plan_node_id, pstate); node->as_pstate = pstate; node->choose_next_subplan = choose_next_subplan_for_leader; @@ -558,7 +558,7 @@ ExecAppendReInitializeDSM(AppendState *node, ParallelContext *pcxt) ParallelAppendState *pstate = node->as_pstate; pstate->pa_next_plan = 0; - memset(pstate->pa_finished, 0, sizeof(bool) * node->as_nplans); + memset(pstate->pa_finished, 0, sizeof(bool) * node->as.nplans); } /* ---------------------------------------------------------------- @@ -571,7 +571,7 @@ ExecAppendReInitializeDSM(AppendState *node, ParallelContext *pcxt) void ExecAppendInitializeWorker(AppendState *node, ParallelWorkerContext *pwcxt) { - node->as_pstate = shm_toc_lookup(pwcxt->toc, node->ps.plan->plan_node_id, false); + node->as_pstate = shm_toc_lookup(pwcxt->toc, node->as.ps.plan->plan_node_id, false); node->choose_next_subplan = choose_next_subplan_for_worker; } @@ -589,7 +589,7 @@ choose_next_subplan_locally(AppendState *node) int nextplan; /* We should never be called when there are no subplans */ - Assert(node->as_nplans > 0); + Assert(node->as.nplans > 0); /* Nothing to do if syncdone */ if (node->as_syncdone) @@ -604,33 +604,33 @@ choose_next_subplan_locally(AppendState *node) */ if (whichplan == INVALID_SUBPLAN_INDEX) { - if (node->as_nasyncplans > 0) + if (node->as.nasyncplans > 0) { /* We'd have filled as_valid_subplans already */ - Assert(node->as_valid_subplans_identified); + Assert(node->as.valid_subplans_identified); } - else if (!node->as_valid_subplans_identified) + else if (!node->as.valid_subplans_identified) { - node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); - node->as_valid_subplans_identified = true; + node->as.valid_subplans = + ExecFindMatchingSubPlans(node->as.prune_state, false, NULL); + node->as.valid_subplans_identified = true; } whichplan = -1; } /* Ensure whichplan is within the expected range */ - Assert(whichplan >= -1 && whichplan <= node->as_nplans); + Assert(whichplan >= -1 && whichplan <= node->as.nplans); - if (ScanDirectionIsForward(node->ps.state->es_direction)) - nextplan = bms_next_member(node->as_valid_subplans, whichplan); + if (ScanDirectionIsForward(node->as.ps.state->es_direction)) + nextplan = bms_next_member(node->as.valid_subplans, whichplan); else - nextplan = bms_prev_member(node->as_valid_subplans, whichplan); + nextplan = bms_prev_member(node->as.valid_subplans, whichplan); if (nextplan < 0) { /* Set as_syncdone if in async mode */ - if (node->as_nasyncplans > 0) + if (node->as.nasyncplans > 0) node->as_syncdone = true; return false; } @@ -654,10 +654,10 @@ choose_next_subplan_for_leader(AppendState *node) ParallelAppendState *pstate = node->as_pstate; /* Backward scan is not supported by parallel-aware plans */ - Assert(ScanDirectionIsForward(node->ps.state->es_direction)); + Assert(ScanDirectionIsForward(node->as.ps.state->es_direction)); /* We should never be called when there are no subplans */ - Assert(node->as_nplans > 0); + Assert(node->as.nplans > 0); LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE); @@ -669,18 +669,18 @@ choose_next_subplan_for_leader(AppendState *node) else { /* Start with last subplan. */ - node->as_whichplan = node->as_nplans - 1; + node->as_whichplan = node->as.nplans - 1; /* * If we've yet to determine the valid subplans then do so now. If * run-time pruning is disabled then the valid subplans will always be * set to all subplans. */ - if (!node->as_valid_subplans_identified) + if (!node->as.valid_subplans_identified) { - node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); - node->as_valid_subplans_identified = true; + node->as.valid_subplans = + ExecFindMatchingSubPlans(node->as.prune_state, false, NULL); + node->as.valid_subplans_identified = true; /* * Mark each invalid plan as finished to allow the loop below to @@ -736,10 +736,10 @@ choose_next_subplan_for_worker(AppendState *node) ParallelAppendState *pstate = node->as_pstate; /* Backward scan is not supported by parallel-aware plans */ - Assert(ScanDirectionIsForward(node->ps.state->es_direction)); + Assert(ScanDirectionIsForward(node->as.ps.state->es_direction)); /* We should never be called when there are no subplans */ - Assert(node->as_nplans > 0); + Assert(node->as.nplans > 0); LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE); @@ -752,11 +752,11 @@ choose_next_subplan_for_worker(AppendState *node) * run-time pruning is disabled then the valid subplans will always be set * to all subplans. */ - else if (!node->as_valid_subplans_identified) + else if (!node->as.valid_subplans_identified) { - node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); - node->as_valid_subplans_identified = true; + node->as.valid_subplans = + ExecFindMatchingSubPlans(node->as.prune_state, false, NULL); + node->as.valid_subplans_identified = true; mark_invalid_subplans_as_finished(node); } @@ -776,7 +776,7 @@ choose_next_subplan_for_worker(AppendState *node) { int nextplan; - nextplan = bms_next_member(node->as_valid_subplans, + nextplan = bms_next_member(node->as.valid_subplans, pstate->pa_next_plan); if (nextplan >= 0) { @@ -789,7 +789,7 @@ choose_next_subplan_for_worker(AppendState *node) * Try looping back to the first valid partial plan, if there is * one. If there isn't, arrange to bail out below. */ - nextplan = bms_next_member(node->as_valid_subplans, + nextplan = bms_next_member(node->as.valid_subplans, node->as_first_partial_plan - 1); pstate->pa_next_plan = nextplan < 0 ? node->as_whichplan : nextplan; @@ -814,7 +814,7 @@ choose_next_subplan_for_worker(AppendState *node) /* Pick the plan we found, and advance pa_next_plan one more time. */ node->as_whichplan = pstate->pa_next_plan; - pstate->pa_next_plan = bms_next_member(node->as_valid_subplans, + pstate->pa_next_plan = bms_next_member(node->as.valid_subplans, pstate->pa_next_plan); /* @@ -823,7 +823,7 @@ choose_next_subplan_for_worker(AppendState *node) */ if (pstate->pa_next_plan < 0) { - int nextplan = bms_next_member(node->as_valid_subplans, + int nextplan = bms_next_member(node->as.valid_subplans, node->as_first_partial_plan - 1); if (nextplan >= 0) @@ -865,16 +865,16 @@ mark_invalid_subplans_as_finished(AppendState *node) Assert(node->as_pstate); /* Shouldn't have been called when run-time pruning is not enabled */ - Assert(node->as_prune_state); + Assert(node->as.prune_state); /* Nothing to do if all plans are valid */ - if (bms_num_members(node->as_valid_subplans) == node->as_nplans) + if (bms_num_members(node->as.valid_subplans) == node->as.nplans) return; /* Mark all non-valid plans as finished */ - for (i = 0; i < node->as_nplans; i++) + for (i = 0; i < node->as.nplans; i++) { - if (!bms_is_member(i, node->as_valid_subplans)) + if (!bms_is_member(i, node->as.valid_subplans)) node->as_pstate->pa_finished[i] = true; } } @@ -896,27 +896,27 @@ ExecAppendAsyncBegin(AppendState *node) int i; /* Backward scan is not supported by async-aware Appends. */ - Assert(ScanDirectionIsForward(node->ps.state->es_direction)); + Assert(ScanDirectionIsForward(node->as.ps.state->es_direction)); /* We should never be called when there are no subplans */ - Assert(node->as_nplans > 0); + Assert(node->as.nplans > 0); /* We should never be called when there are no async subplans. */ - Assert(node->as_nasyncplans > 0); + Assert(node->as.nasyncplans > 0); /* If we've yet to determine the valid subplans then do so now. */ - if (!node->as_valid_subplans_identified) + if (!node->as.valid_subplans_identified) { - node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); - node->as_valid_subplans_identified = true; + node->as.valid_subplans = + ExecFindMatchingSubPlans(node->as.prune_state, false, NULL); + node->as.valid_subplans_identified = true; classify_matching_subplans(node); } /* Initialize state variables. */ - node->as_syncdone = bms_is_empty(node->as_valid_subplans); - node->as_nasyncremain = bms_num_members(node->as_valid_asyncplans); + node->as_syncdone = bms_is_empty(node->as.valid_subplans); + node->as_nasyncremain = bms_num_members(node->as.valid_asyncplans); /* Nothing to do if there are no valid async subplans. */ if (node->as_nasyncremain == 0) @@ -924,9 +924,9 @@ ExecAppendAsyncBegin(AppendState *node) /* Make a request for each of the valid async subplans. */ i = -1; - while ((i = bms_next_member(node->as_valid_asyncplans, i)) >= 0) + while ((i = bms_next_member(node->as.valid_asyncplans, i)) >= 0) { - AsyncRequest *areq = node->as_asyncrequests[i]; + AsyncRequest *areq = node->as.asyncrequests[i]; Assert(areq->request_index == i); @@ -996,7 +996,7 @@ ExecAppendAsyncGetNext(AppendState *node, TupleTableSlot **result) if (node->as_syncdone) { Assert(node->as_nasyncremain == 0); - *result = ExecClearTuple(node->ps.ps_ResultTupleSlot); + *result = ExecClearTuple(node->as.ps.ps_ResultTupleSlot); return true; } @@ -1016,7 +1016,7 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result) int i; /* Nothing to do if there are no async subplans needing a new request. */ - if (bms_is_empty(node->as_needrequest)) + if (bms_is_empty(node->as.needrequest)) { Assert(node->as_nasyncresults == 0); return false; @@ -1029,17 +1029,17 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result) if (node->as_nasyncresults > 0) { --node->as_nasyncresults; - *result = node->as_asyncresults[node->as_nasyncresults]; + *result = node->as.asyncresults[node->as_nasyncresults]; return true; } /* Make a new request for each of the async subplans that need it. */ - needrequest = node->as_needrequest; - node->as_needrequest = NULL; + needrequest = node->as.needrequest; + node->as.needrequest = NULL; i = -1; while ((i = bms_next_member(needrequest, i)) >= 0) { - AsyncRequest *areq = node->as_asyncrequests[i]; + AsyncRequest *areq = node->as.asyncrequests[i]; /* Do the actual work. */ ExecAsyncRequest(areq); @@ -1050,7 +1050,7 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result) if (node->as_nasyncresults > 0) { --node->as_nasyncresults; - *result = node->as_asyncresults[node->as_nasyncresults]; + *result = node->as.asyncresults[node->as_nasyncresults]; return true; } @@ -1066,7 +1066,7 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result) static void ExecAppendAsyncEventWait(AppendState *node) { - int nevents = node->as_nasyncplans + 2; + int nevents = node->as.nasyncplans + 2; long timeout = node->as_syncdone ? -1 : 0; WaitEvent occurred_event[EVENT_BUFFER_SIZE]; int noccurred; @@ -1075,16 +1075,16 @@ ExecAppendAsyncEventWait(AppendState *node) /* We should never be called when there are no valid async subplans. */ Assert(node->as_nasyncremain > 0); - Assert(node->as_eventset == NULL); - node->as_eventset = CreateWaitEventSet(CurrentResourceOwner, nevents); - AddWaitEventToSet(node->as_eventset, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET, + Assert(node->as.eventset == NULL); + node->as.eventset = CreateWaitEventSet(CurrentResourceOwner, nevents); + AddWaitEventToSet(node->as.eventset, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET, NULL, NULL); /* Give each waiting subplan a chance to add an event. */ i = -1; - while ((i = bms_next_member(node->as_asyncplans, i)) >= 0) + while ((i = bms_next_member(node->as.asyncplans, i)) >= 0) { - AsyncRequest *areq = node->as_asyncrequests[i]; + AsyncRequest *areq = node->as.asyncrequests[i]; if (areq->callback_pending) ExecAsyncConfigureWait(areq); @@ -1094,10 +1094,10 @@ ExecAppendAsyncEventWait(AppendState *node) * No need for further processing if none of the subplans configured any * events. */ - if (GetNumRegisteredWaitEvents(node->as_eventset) == 1) + if (GetNumRegisteredWaitEvents(node->as.eventset) == 1) { - FreeWaitEventSet(node->as_eventset); - node->as_eventset = NULL; + FreeWaitEventSet(node->as.eventset); + node->as.eventset = NULL; return; } @@ -1113,7 +1113,7 @@ ExecAppendAsyncEventWait(AppendState *node) * we cannot change it now. The pattern has possibly been copied to other * extensions too. */ - AddWaitEventToSet(node->as_eventset, WL_LATCH_SET, PGINVALID_SOCKET, + AddWaitEventToSet(node->as.eventset, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL); /* Return at most EVENT_BUFFER_SIZE events in one call. */ @@ -1124,10 +1124,10 @@ ExecAppendAsyncEventWait(AppendState *node) * If the timeout is -1, wait until at least one event occurs. If the * timeout is 0, poll for events, but do not wait at all. */ - noccurred = WaitEventSetWait(node->as_eventset, timeout, occurred_event, + noccurred = WaitEventSetWait(node->as.eventset, timeout, occurred_event, nevents, WAIT_EVENT_APPEND_READY); - FreeWaitEventSet(node->as_eventset); - node->as_eventset = NULL; + FreeWaitEventSet(node->as.eventset); + node->as.eventset = NULL; if (noccurred == 0) return; @@ -1200,14 +1200,14 @@ ExecAsyncAppendResponse(AsyncRequest *areq) } /* Save result so we can return it. */ - Assert(node->as_nasyncresults < node->as_nasyncplans); - node->as_asyncresults[node->as_nasyncresults++] = slot; + Assert(node->as_nasyncresults < node->as.nasyncplans); + node->as.asyncresults[node->as_nasyncresults++] = slot; /* * Mark the subplan that returned a result as ready for a new request. We * don't launch another one here immediately because it might complete. */ - node->as_needrequest = bms_add_member(node->as_needrequest, + node->as.needrequest = bms_add_member(node->as.needrequest, areq->request_index); } @@ -1224,11 +1224,11 @@ classify_matching_subplans(AppendState *node) { Bitmapset *valid_asyncplans; - Assert(node->as_valid_subplans_identified); - Assert(node->as_valid_asyncplans == NULL); + Assert(node->as.valid_subplans_identified); + Assert(node->as.valid_asyncplans == NULL); /* Nothing to do if there are no valid subplans. */ - if (bms_is_empty(node->as_valid_subplans)) + if (bms_is_empty(node->as.valid_subplans)) { node->as_syncdone = true; node->as_nasyncremain = 0; @@ -1236,20 +1236,20 @@ classify_matching_subplans(AppendState *node) } /* Nothing to do if there are no valid async subplans. */ - if (!bms_overlap(node->as_valid_subplans, node->as_asyncplans)) + if (!bms_overlap(node->as.valid_subplans, node->as.asyncplans)) { node->as_nasyncremain = 0; return; } /* Get valid async subplans. */ - valid_asyncplans = bms_intersect(node->as_asyncplans, - node->as_valid_subplans); + valid_asyncplans = bms_intersect(node->as.asyncplans, + node->as.valid_subplans); /* Adjust the valid subplans to contain sync subplans only. */ - node->as_valid_subplans = bms_del_members(node->as_valid_subplans, + node->as.valid_subplans = bms_del_members(node->as.valid_subplans, valid_asyncplans); /* Save valid async subplans. */ - node->as_valid_asyncplans = valid_asyncplans; + node->as.valid_asyncplans = valid_asyncplans; } diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 0173074d85d..e4cdbcc5eb2 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -80,12 +80,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) /* * create new MergeAppendState for our node */ - mergestate->ps.plan = (Plan *) node; - mergestate->ps.state = estate; - mergestate->ps.ExecProcNode = ExecMergeAppend; + mergestate->as.ps.plan = (Plan *) node; + mergestate->as.ps.state = estate; + mergestate->as.ps.ExecProcNode = ExecMergeAppend; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_index >= 0) + if (node->ab.part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -94,12 +94,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * subplans to initialize (validsubplans) by taking into account the * result of performing initial pruning if any. */ - prunestate = ExecInitPartitionExecPruning(&mergestate->ps, - list_length(node->mergeplans), - node->part_prune_index, - node->apprelids, + prunestate = ExecInitPartitionExecPruning(&mergestate->as.ps, + list_length(node->ab.subplans), + node->ab.part_prune_index, + node->ab.apprelids, &validsubplans); - mergestate->ms_prune_state = prunestate; + mergestate->as.prune_state = prunestate; nplans = bms_num_members(validsubplans); /* @@ -108,25 +108,25 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * later calls to ExecFindMatchingSubPlans. */ if (!prunestate->do_exec_prune && nplans > 0) - mergestate->ms_valid_subplans = bms_add_range(NULL, 0, nplans - 1); + mergestate->as.valid_subplans = bms_add_range(NULL, 0, nplans - 1); } else { - nplans = list_length(node->mergeplans); + nplans = list_length(node->ab.subplans); /* * When run-time partition pruning is not enabled we can just mark all * subplans as valid; they must also all be initialized. */ Assert(nplans > 0); - mergestate->ms_valid_subplans = validsubplans = + mergestate->as.valid_subplans = validsubplans = bms_add_range(NULL, 0, nplans - 1); - mergestate->ms_prune_state = NULL; + mergestate->as.prune_state = NULL; } mergeplanstates = palloc_array(PlanState *, nplans); - mergestate->mergeplans = mergeplanstates; - mergestate->ms_nplans = nplans; + mergestate->as.plans = mergeplanstates; + mergestate->as.nplans = nplans; mergestate->ms_slots = palloc0_array(TupleTableSlot *, nplans); mergestate->ms_heap = binaryheap_allocate(nplans, heap_compare_slots, @@ -140,7 +140,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) i = -1; while ((i = bms_next_member(validsubplans, i)) >= 0) { - Plan *initNode = (Plan *) list_nth(node->mergeplans, i); + Plan *initNode = (Plan *) list_nth(node->ab.subplans, i); mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags); } @@ -157,20 +157,20 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) mergeops = ExecGetCommonSlotOps(mergeplanstates, j); if (mergeops != NULL) { - ExecInitResultTupleSlotTL(&mergestate->ps, mergeops); + ExecInitResultTupleSlotTL(&mergestate->as.ps, mergeops); } else { - ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual); + ExecInitResultTupleSlotTL(&mergestate->as.ps, &TTSOpsVirtual); /* show that the output slot type is not fixed */ - mergestate->ps.resultopsset = true; - mergestate->ps.resultopsfixed = false; + mergestate->as.ps.resultopsset = true; + mergestate->as.ps.resultopsfixed = false; } /* * Miscellaneous initialization */ - mergestate->ps.ps_ProjInfo = NULL; + mergestate->as.ps.ps_ProjInfo = NULL; /* * initialize sort-key information @@ -225,26 +225,26 @@ ExecMergeAppend(PlanState *pstate) if (!node->ms_initialized) { /* Nothing to do if all subplans were pruned */ - if (node->ms_nplans == 0) - return ExecClearTuple(node->ps.ps_ResultTupleSlot); + if (node->as.nplans == 0) + return ExecClearTuple(node->as.ps.ps_ResultTupleSlot); /* * If we've yet to determine the valid subplans then do so now. If * run-time pruning is disabled then the valid subplans will always be * set to all subplans. */ - if (node->ms_valid_subplans == NULL) - node->ms_valid_subplans = - ExecFindMatchingSubPlans(node->ms_prune_state, false, NULL); + if (node->as.valid_subplans == NULL) + node->as.valid_subplans = + ExecFindMatchingSubPlans(node->as.prune_state, false, NULL); /* * First time through: pull the first tuple from each valid subplan, * and set up the heap. */ i = -1; - while ((i = bms_next_member(node->ms_valid_subplans, i)) >= 0) + while ((i = bms_next_member(node->as.valid_subplans, i)) >= 0) { - node->ms_slots[i] = ExecProcNode(node->mergeplans[i]); + node->ms_slots[i] = ExecProcNode(node->as.plans[i]); if (!TupIsNull(node->ms_slots[i])) binaryheap_add_unordered(node->ms_heap, Int32GetDatum(i)); } @@ -262,7 +262,7 @@ ExecMergeAppend(PlanState *pstate) * to not pull tuples until necessary.) */ i = DatumGetInt32(binaryheap_first(node->ms_heap)); - node->ms_slots[i] = ExecProcNode(node->mergeplans[i]); + node->ms_slots[i] = ExecProcNode(node->as.plans[i]); if (!TupIsNull(node->ms_slots[i])) binaryheap_replace_first(node->ms_heap, Int32GetDatum(i)); else @@ -272,7 +272,7 @@ ExecMergeAppend(PlanState *pstate) if (binaryheap_empty(node->ms_heap)) { /* All the subplans are exhausted, and so is the heap */ - result = ExecClearTuple(node->ps.ps_ResultTupleSlot); + result = ExecClearTuple(node->as.ps.ps_ResultTupleSlot); } else { @@ -343,8 +343,8 @@ ExecEndMergeAppend(MergeAppendState *node) /* * get information from the node */ - mergeplans = node->mergeplans; - nplans = node->ms_nplans; + mergeplans = node->as.plans; + nplans = node->as.nplans; /* * shut down each of the subscans @@ -363,24 +363,24 @@ ExecReScanMergeAppend(MergeAppendState *node) * we'd better unset the valid subplans so that they are reselected for * the new parameter values. */ - if (node->ms_prune_state && - bms_overlap(node->ps.chgParam, - node->ms_prune_state->execparamids)) + if (node->as.prune_state && + bms_overlap(node->as.ps.chgParam, + node->as.prune_state->execparamids)) { - bms_free(node->ms_valid_subplans); - node->ms_valid_subplans = NULL; + bms_free(node->as.valid_subplans); + node->as.valid_subplans = NULL; } - for (i = 0; i < node->ms_nplans; i++) + for (i = 0; i < node->as.nplans; i++) { - PlanState *subnode = node->mergeplans[i]; + PlanState *subnode = node->as.plans[i]; /* * ExecReScan doesn't know about my subplans, so I have to do * changed-parameter signaling myself. */ - if (node->ps.chgParam != NULL) - UpdateChangedParamSet(subnode, node->ps.chgParam); + if (node->as.ps.chgParam != NULL) + UpdateChangedParamSet(subnode, node->as.ps.chgParam); /* * If chgParam of subnode is not null then plan will be re-scanned by diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 2a2e00b372e..7f18282dd81 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -4904,14 +4904,9 @@ planstate_tree_walker_impl(PlanState *planstate, switch (nodeTag(plan)) { case T_Append: - if (planstate_walk_members(((AppendState *) planstate)->appendplans, - ((AppendState *) planstate)->as_nplans, - walker, context)) - return true; - break; case T_MergeAppend: - if (planstate_walk_members(((MergeAppendState *) planstate)->mergeplans, - ((MergeAppendState *) planstate)->ms_nplans, + if (planstate_walk_members(((AppendBaseState *) planstate)->plans, + ((AppendBaseState *) planstate)->nplans, walker, context)) return true; break; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 7816558adec..828f468f65d 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1246,12 +1246,12 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) * child plans, to make cross-checking the sort info easier. */ plan = makeNode(Append); - plan->plan.targetlist = tlist; - plan->plan.qual = NIL; - plan->plan.lefttree = NULL; - plan->plan.righttree = NULL; - plan->apprelids = rel->relids; - plan->child_append_relid_sets = best_path->child_append_relid_sets; + plan->ab.plan.targetlist = tlist; + plan->ab.plan.qual = NIL; + plan->ab.plan.lefttree = NULL; + plan->ab.plan.righttree = NULL; + plan->ab.apprelids = rel->relids; + plan->ab.child_append_relid_sets = best_path->child_append_relid_sets; if (pathkeys != NIL) { @@ -1270,7 +1270,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) &nodeSortOperators, &nodeCollations, &nodeNullsFirst); - tlist_was_changed = (orig_tlist_length != list_length(plan->plan.targetlist)); + tlist_was_changed = (orig_tlist_length != list_length(plan->ab.plan.targetlist)); } /* If appropriate, consider async append */ @@ -1380,7 +1380,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) } /* Set below if we find quals that we can use to run-time prune */ - plan->part_prune_index = -1; + plan->ab.part_prune_index = -1; /* * If any quals exist, they may be useful to perform further partition @@ -1405,16 +1405,16 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) } if (prunequal != NIL) - plan->part_prune_index = make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + plan->ab.part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } - plan->appendplans = subplans; + plan->ab.subplans = subplans; plan->nasyncplans = nasyncplans; plan->first_partial_plan = best_path->first_partial_path; - copy_generic_path_info(&plan->plan, (Path *) best_path); + copy_generic_path_info(&plan->ab.plan, (Path *) best_path); /* * If prepare_sort_from_pathkeys added sort columns, but we were told to @@ -1423,9 +1423,9 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) */ if (tlist_was_changed && (flags & (CP_EXACT_TLIST | CP_SMALL_TLIST))) { - tlist = list_copy_head(plan->plan.targetlist, orig_tlist_length); + tlist = list_copy_head(plan->ab.plan.targetlist, orig_tlist_length); return inject_projection_plan((Plan *) plan, tlist, - plan->plan.parallel_safe); + plan->ab.plan.parallel_safe); } else return (Plan *) plan; @@ -1443,7 +1443,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, int flags) { MergeAppend *node = makeNode(MergeAppend); - Plan *plan = &node->plan; + Plan *plan = &node->ab.plan; List *tlist = build_path_tlist(root, &best_path->path); int orig_tlist_length = list_length(tlist); bool tlist_was_changed; @@ -1463,8 +1463,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, plan->qual = NIL; plan->lefttree = NULL; plan->righttree = NULL; - node->apprelids = rel->relids; - node->child_append_relid_sets = best_path->child_append_relid_sets; + node->ab.apprelids = rel->relids; + node->ab.child_append_relid_sets = best_path->child_append_relid_sets; /* * Compute sort column info, and adjust MergeAppend's tlist as needed. @@ -1570,7 +1570,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, } /* Set below if we find quals that we can use to run-time prune */ - node->part_prune_index = -1; + node->ab.part_prune_index = -1; /* * If any quals exist, they may be useful to perform further partition @@ -1587,12 +1587,12 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, Assert(best_path->path.param_info == NULL); if (prunequal != NIL) - node->part_prune_index = make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + node->ab.part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } - node->mergeplans = subplans; + node->ab.subplans = subplans; /* * If prepare_sort_from_pathkeys added sort columns, but we were told to diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index ff0e875f2a2..6d2498a70d2 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -149,12 +149,9 @@ static void set_foreignscan_references(PlannerInfo *root, static void set_customscan_references(PlannerInfo *root, CustomScan *cscan, int rtoffset); -static Plan *set_append_references(PlannerInfo *root, - Append *aplan, - int rtoffset); -static Plan *set_mergeappend_references(PlannerInfo *root, - MergeAppend *mplan, - int rtoffset); +static Plan *set_appendbase_references(PlannerInfo *root, + AppendBase *plan, + int rtoffset); static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset); static Relids offset_relid_set(Relids relids, int rtoffset); static Node *fix_scan_expr(PlannerInfo *root, Node *node, @@ -1301,15 +1298,11 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } break; case T_Append: - /* Needs special treatment, see comments below */ - return set_append_references(root, - (Append *) plan, - rtoffset); case T_MergeAppend: /* Needs special treatment, see comments below */ - return set_mergeappend_references(root, - (MergeAppend *) plan, - rtoffset); + return set_appendbase_references(root, + (AppendBase *) plan, + rtoffset); case T_RecursiveUnion: /* This doesn't evaluate targetlist or check quals either */ set_dummy_tlist_references(plan, rtoffset); @@ -1796,7 +1789,7 @@ set_customscan_references(PlannerInfo *root, /* * register_partpruneinfo - * Subroutine for set_append_references and set_mergeappend_references + * Subroutine for set_appendbase_references * * Add the PartitionPruneInfo from root->partPruneInfos at the given index * into PlannerGlobal->partPruneInfos and return its index there. @@ -1863,158 +1856,84 @@ register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset) } /* - * set_append_references - * Do set_plan_references processing on an Append - * - * We try to strip out the Append entirely; if we can't, we have - * to do the normal processing on it. + * set_appendbase_references + * Do set_plan_references processing on an Append or MergeAppend + * + * We try to strip out the node entirely; if we can't, we have to do the + * normal processing on it. Append and MergeAppend behave identically here + * (both are represented via the common AppendBase struct), so this is + * shared between them; the only thing that differs is which NodeTag to + * report as elided, and nodeTag(plan) already gives us that. */ static Plan * -set_append_references(PlannerInfo *root, - Append *aplan, - int rtoffset) +set_appendbase_references(PlannerInfo *root, + AppendBase *plan, + int rtoffset) { ListCell *l; /* - * Append, like Sort et al, doesn't actually evaluate its targetlist or - * check quals. If it's got exactly one child plan, then it's not doing - * anything useful at all, and we can strip it out. + * Append/MergeAppend, like Sort et al, doesn't actually evaluate its + * targetlist or check quals. If it's got exactly one child plan, then + * it's not doing anything useful at all, and we can strip it out. */ - Assert(aplan->plan.qual == NIL); + Assert(plan->plan.qual == NIL); /* First, we gotta recurse on the children */ - foreach(l, aplan->appendplans) + foreach(l, plan->subplans) { lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } /* - * See if it's safe to get rid of the Append entirely. For this to be - * safe, there must be only one child plan and that child plan's parallel - * awareness must match the Append's. The reason for the latter is that - * if the Append is parallel aware and the child is not, then the calling - * plan may execute the non-parallel aware child multiple times. (If you - * change these rules, update create_append_path to match.) + * See if it's safe to get rid of the node entirely. For this to be + * safe, there must be only one child plan and that child plan's + * parallel awareness must match the node's. The reason for the latter + * is that if the node is parallel aware and the child is not, then the + * calling plan may execute the non-parallel aware child multiple times. + * (If you change these rules, update create_append_path and + * create_merge_append_path to match.) */ - if (list_length(aplan->appendplans) == 1) + if (list_length(plan->subplans) == 1) { - Plan *p = (Plan *) linitial(aplan->appendplans); + Plan *p = (Plan *) linitial(plan->subplans); - if (p->parallel_aware == aplan->plan.parallel_aware) + if (p->parallel_aware == plan->plan.parallel_aware) { Plan *result; - result = clean_up_removed_plan_level((Plan *) aplan, p); + result = clean_up_removed_plan_level((Plan *) plan, p); - /* Remember that we removed an Append */ - record_elided_node(root->glob, p->plan_node_id, T_Append, - offset_relid_set(aplan->apprelids, rtoffset)); + /* Remember that we removed an Append/MergeAppend */ + record_elided_node(root->glob, p->plan_node_id, nodeTag(plan), + offset_relid_set(plan->apprelids, rtoffset)); return result; } } /* - * Otherwise, clean up the Append as needed. It's okay to do this after + * Otherwise, clean up the node as needed. It's okay to do this after * recursing to the children, because set_dummy_tlist_references doesn't * look at those. */ - set_dummy_tlist_references((Plan *) aplan, rtoffset); - - aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset); - - /* - * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. - * Also update the RT indexes present in it to add the offset. - */ - if (aplan->part_prune_index >= 0) - aplan->part_prune_index = - register_partpruneinfo(root, aplan->part_prune_index, rtoffset); - - /* We don't need to recurse to lefttree or righttree ... */ - Assert(aplan->plan.lefttree == NULL); - Assert(aplan->plan.righttree == NULL); - - return (Plan *) aplan; -} - -/* - * set_mergeappend_references - * Do set_plan_references processing on a MergeAppend - * - * We try to strip out the MergeAppend entirely; if we can't, we have - * to do the normal processing on it. - */ -static Plan * -set_mergeappend_references(PlannerInfo *root, - MergeAppend *mplan, - int rtoffset) -{ - ListCell *l; - - /* - * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist - * or check quals. If it's got exactly one child plan, then it's not - * doing anything useful at all, and we can strip it out. - */ - Assert(mplan->plan.qual == NIL); - - /* First, we gotta recurse on the children */ - foreach(l, mplan->mergeplans) - { - lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); - } - - /* - * See if it's safe to get rid of the MergeAppend entirely. For this to - * be safe, there must be only one child plan and that child plan's - * parallel awareness must match the MergeAppend's. The reason for the - * latter is that if the MergeAppend is parallel aware and the child is - * not, then the calling plan may execute the non-parallel aware child - * multiple times. (If you change these rules, update - * create_merge_append_path to match.) - */ - if (list_length(mplan->mergeplans) == 1) - { - Plan *p = (Plan *) linitial(mplan->mergeplans); - - if (p->parallel_aware == mplan->plan.parallel_aware) - { - Plan *result; - - result = clean_up_removed_plan_level((Plan *) mplan, p); - - /* Remember that we removed a MergeAppend */ - record_elided_node(root->glob, p->plan_node_id, T_MergeAppend, - offset_relid_set(mplan->apprelids, rtoffset)); - - return result; - } - } - - /* - * Otherwise, clean up the MergeAppend as needed. It's okay to do this - * after recursing to the children, because set_dummy_tlist_references - * doesn't look at those. - */ - set_dummy_tlist_references((Plan *) mplan, rtoffset); + set_dummy_tlist_references((Plan *) plan, rtoffset); - mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset); + plan->apprelids = offset_relid_set(plan->apprelids, rtoffset); /* * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. * Also update the RT indexes present in it to add the offset. */ - if (mplan->part_prune_index >= 0) - mplan->part_prune_index = - register_partpruneinfo(root, mplan->part_prune_index, rtoffset); + if (plan->part_prune_index >= 0) + plan->part_prune_index = + register_partpruneinfo(root, plan->part_prune_index, rtoffset); /* We don't need to recurse to lefttree or righttree ... */ - Assert(mplan->plan.lefttree == NULL); - Assert(mplan->plan.righttree == NULL); + Assert(plan->plan.lefttree == NULL); + Assert(plan->plan.righttree == NULL); - return (Plan *) mplan; + return (Plan *) plan; } /* diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 6aa8971c95d..e6758724744 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2906,7 +2906,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, case T_Append: { - foreach(l, ((Append *) plan)->appendplans) + foreach(l, ((Append *) plan)->ab.subplans) { context.paramids = bms_add_members(context.paramids, @@ -2921,7 +2921,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, case T_MergeAppend: { - foreach(l, ((MergeAppend *) plan)->mergeplans) + foreach(l, ((MergeAppend *) plan)->ab.subplans) { context.paramids = bms_add_members(context.paramids, diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 88de5c0481c..e12b9d0d7f7 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5522,9 +5522,9 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan) * natural choice. */ if (IsA(plan, Append)) - dpns->outer_plan = linitial(((Append *) plan)->appendplans); + dpns->outer_plan = linitial(((Append *) plan)->ab.subplans); else if (IsA(plan, MergeAppend)) - dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans); + dpns->outer_plan = linitial(((MergeAppend *) plan)->ab.subplans); else dpns->outer_plan = outerPlan(plan); @@ -8506,10 +8506,10 @@ resolve_special_varno(Node *node, deparse_context *context, if (IsA(dpns->plan, Append)) context->appendparents = bms_union(context->appendparents, - ((Append *) dpns->plan)->apprelids); + ((Append *) dpns->plan)->ab.apprelids); else if (IsA(dpns->plan, MergeAppend)) context->appendparents = bms_union(context->appendparents, - ((MergeAppend *) dpns->plan)->apprelids); + ((MergeAppend *) dpns->plan)->ab.apprelids); push_child_plan(dpns, dpns->outer_plan, &save_dpns); resolve_special_varno((Node *) tle->expr, context, diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index e64fd8c7ea3..006be3ccf3e 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1513,6 +1513,39 @@ typedef struct ModifyTableState List *mt_fdwPrivLists; } ModifyTableState; +/* ---------------- + * AppendBaseState information + * + * Common base for AppendState and MergeAppendState. + * Contains fields shared by both node types: the array of subplan + * states, asynchronous execution infrastructure, and partition + * pruning state. + * ---------------- + */ +typedef struct AppendBaseState +{ + pg_node_attr(abstract) + + PlanState ps; /* its first field is NodeTag */ + PlanState **plans; /* array of PlanStates for my inputs */ + int nplans; + + /* Asynchronous execution state */ + Bitmapset *asyncplans; /* asynchronous plans indexes */ + int nasyncplans; /* # of asynchronous plans */ + AsyncRequest **asyncrequests; /* array of AsyncRequests */ + TupleTableSlot **asyncresults; /* unreturned results of async plans */ + Bitmapset *needrequest; /* asynchronous plans needing a new request */ + struct WaitEventSet *eventset; /* WaitEventSet used to configure file + * descriptor wait events */ + + /* Partition pruning state */ + struct PartitionPruneState *prune_state; + bool valid_subplans_identified; /* is valid_subplans valid? */ + Bitmapset *valid_subplans; + Bitmapset *valid_asyncplans; /* valid asynchronous plans indexes */ +} AppendBaseState; + /* ---------------- * AppendState information * @@ -1534,30 +1567,21 @@ struct PartitionPruneState; struct AppendState { - PlanState ps; /* its first field is NodeTag */ - PlanState **appendplans; /* array of PlanStates for my inputs */ - int as_nplans; + AppendBaseState as; /* its first field is NodeTag */ + int as_whichplan; bool as_begun; /* false means need to initialize */ - Bitmapset *as_asyncplans; /* asynchronous plans indexes */ - int as_nasyncplans; /* # of asynchronous plans */ - AsyncRequest **as_asyncrequests; /* array of AsyncRequests */ - TupleTableSlot **as_asyncresults; /* unreturned results of async plans */ - int as_nasyncresults; /* # of valid entries in as_asyncresults */ + int as_nasyncresults; /* # of valid entries in asyncresults */ bool as_syncdone; /* true if all synchronous plans done in * asynchronous mode, else false */ int as_nasyncremain; /* # of remaining asynchronous plans */ - Bitmapset *as_needrequest; /* asynchronous plans needing a new request */ - struct WaitEventSet *as_eventset; /* WaitEventSet used to configure file - * descriptor wait events */ - int as_first_partial_plan; /* Index of 'appendplans' containing - * the first partial plan */ + int as_first_partial_plan; /* Index of 'as.plans' containing the + * first partial plan */ + + /* Parallel append specific */ ParallelAppendState *as_pstate; /* parallel coordination info */ Size pstate_len; /* size of parallel coordination info */ - struct PartitionPruneState *as_prune_state; - bool as_valid_subplans_identified; /* is as_valid_subplans valid? */ - Bitmapset *as_valid_subplans; - Bitmapset *as_valid_asyncplans; /* valid asynchronous plans indexes */ + bool (*choose_next_subplan) (AppendState *); }; @@ -1578,16 +1602,13 @@ struct AppendState */ typedef struct MergeAppendState { - PlanState ps; /* its first field is NodeTag */ - PlanState **mergeplans; /* array of PlanStates for my inputs */ - int ms_nplans; + AppendBaseState as; /* its first field is NodeTag */ + int ms_nkeys; SortSupport ms_sortkeys; /* array of length ms_nkeys */ TupleTableSlot **ms_slots; /* array of length ms_nplans */ struct binaryheap *ms_heap; /* binary heap of slot indices */ bool ms_initialized; /* are subplans started? */ - struct PartitionPruneState *ms_prune_state; - Bitmapset *ms_valid_subplans; } MergeAppendState; /* ---------------- diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 14a1dfed2b9..072b6aa0a90 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -391,38 +391,48 @@ typedef struct ModifyTable struct PartitionPruneInfo; /* forward reference to struct below */ /* ---------------- - * Append node - - * Generate the concatenation of the results of sub-plans. + * AppendBase node - + * Common base for Append and MergeAppend plan nodes. + * Contains fields shared by both node types: the list of subplans, + * appendrel identifiers, and run-time partition pruning info. * ---------------- */ -typedef struct Append +typedef struct AppendBase { - Plan plan; + pg_node_attr(abstract) - /* RTIs of appendrel(s) formed by this node */ - Bitmapset *apprelids; + Plan plan; /* its first field is NodeTag */ + Bitmapset *apprelids; /* RTIs of appendrel(s) formed by this node */ + List *child_append_relid_sets; /* sets of RTIs of appendrels + * consolidated into this node */ + List *subplans; /* List of Plans (formerly + * appendplans/mergeplans) */ - /* sets of RTIs of appendrels consolidated into this node */ - List *child_append_relid_sets; + /* + * Index into PlannedStmt.partPruneInfos and parallel lists in EState: + * es_part_prune_states and es_part_prune_results. Set to -1 if no + * run-time pruning is used. + */ + int part_prune_index; +} AppendBase; - /* plans to run */ - List *appendplans; +/* ---------------- + * Append node - + * Generate the concatenation of the results of sub-plans. + * ---------------- + */ +typedef struct Append +{ + AppendBase ab; /* its first field is NodeTag */ /* # of asynchronous plans */ int nasyncplans; /* - * All 'appendplans' preceding this index are non-partial plans. All - * 'appendplans' from this index onwards are partial plans. + * All 'subplans' preceding this index are non-partial plans. All + * 'subplans' from this index onwards are partial plans. */ int first_partial_plan; - - /* - * Index into PlannedStmt.partPruneInfos and parallel lists in EState: - * es_part_prune_states and es_part_prune_results. Set to -1 if no - * run-time pruning is used. - */ - int part_prune_index; } Append; /* ---------------- @@ -432,16 +442,7 @@ typedef struct Append */ typedef struct MergeAppend { - Plan plan; - - /* RTIs of appendrel(s) formed by this node */ - Bitmapset *apprelids; - - /* sets of RTIs of appendrels consolidated into this node */ - List *child_append_relid_sets; - - /* plans to run */ - List *mergeplans; + AppendBase ab; /* its first field is NodeTag */ /* these fields are just like the sort-key info in struct Sort: */ @@ -459,13 +460,6 @@ typedef struct MergeAppend /* NULLS FIRST/LAST directions */ bool *nullsFirst pg_node_attr(array_size(numCols)); - - /* - * Index into PlannedStmt.partPruneInfos and parallel lists in EState: - * es_part_prune_states and es_part_prune_results. Set to -1 if no - * run-time pruning is used. - */ - int part_prune_index; } MergeAppend; /* ---------------- diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 117e7379f10..c9d9a650e47 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -128,6 +128,8 @@ AnlExprData AnlIndexData AnyArrayType Append +AppendBase +AppendBaseState AppendPath AppendPathInput AppendRelInfo -- 2.39.5 (Apple Git-154)