From d3546fe99a70c966087592c8d49f9852675f020a Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 5 Apr 2026 04:00:15 +0300 Subject: [PATCH v18 2/5] 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 | 26 +-- 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 | 8 +- src/backend/optimizer/plan/createplan.c | 46 ++-- src/backend/optimizer/plan/setrefs.c | 48 ++-- 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, 351 insertions(+), 334 deletions(-) diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c index 715eda8dc56..196f4286a8a 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 0467f9b12ba..768ab35e6b3 100644 --- a/contrib/pg_plan_advice/pgpa_scan.c +++ b/contrib/pg_plan_advice/pgpa_scan.c @@ -149,7 +149,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. */ @@ -161,7 +161,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 e32684d2075..f2a34a1cf76 100644 --- a/contrib/pg_plan_advice/pgpa_walker.c +++ b/contrib/pg_plan_advice/pgpa_walker.c @@ -440,14 +440,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: @@ -570,9 +570,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 cc8ec24c30e..aa5c70e5394 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -2413,8 +2413,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 && @@ -2422,8 +2422,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? */ @@ -7215,7 +7215,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); @@ -7257,7 +7257,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 73eaaf176ac..6b270f358d7 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1226,11 +1226,11 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used) break; case T_Append: *rels_used = bms_add_members(*rels_used, - ((Append *) plan)->apprelids); + ((Append *) plan)->ab.apprelids); break; case T_MergeAppend: *rels_used = bms_add_members(*rels_used, - ((MergeAppend *) plan)->apprelids); + ((MergeAppend *) plan)->ab.apprelids); break; case T_Result: *rels_used = bms_add_members(*rels_used, @@ -1274,7 +1274,7 @@ plan_is_disabled(Plan *plan) * includes any run-time pruned children. Ignoring those could give * us the incorrect number of disabled nodes. */ - foreach(lc, aplan->appendplans) + foreach(lc, aplan->ab.subplans) { Plan *subplan = lfirst(lc); @@ -1291,7 +1291,7 @@ plan_is_disabled(Plan *plan) * includes any run-time pruned children. Ignoring those could give * us the incorrect number of disabled nodes. */ - foreach(lc, maplan->mergeplans) + foreach(lc, maplan->ab.subplans) { Plan *subplan = lfirst(lc); @@ -2339,13 +2339,13 @@ ExplainNode(PlanState *planstate, List *ancestors, switch (nodeTag(plan)) { case T_Append: - ExplainMissingMembers(((AppendState *) planstate)->as_nplans, - list_length(((Append *) plan)->appendplans), + ExplainMissingMembers(((AppendState *) planstate)->as.nplans, + list_length(((Append *) plan)->ab.subplans), es); break; case T_MergeAppend: - ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans, - list_length(((MergeAppend *) plan)->mergeplans), + ExplainMissingMembers(((MergeAppendState *) planstate)->as.nplans, + list_length(((MergeAppend *) plan)->ab.subplans), es); break; default: @@ -2389,13 +2389,13 @@ ExplainNode(PlanState *planstate, List *ancestors, switch (nodeTag(plan)) { case T_Append: - ExplainMemberNodes(((AppendState *) planstate)->appendplans, - ((AppendState *) planstate)->as_nplans, + ExplainMemberNodes(((AppendState *) planstate)->as.plans, + ((AppendState *) planstate)->as.nplans, ancestors, es); break; case T_MergeAppend: - ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans, - ((MergeAppendState *) planstate)->ms_nplans, + ExplainMemberNodes(((MergeAppendState *) planstate)->as.plans, + ((MergeAppendState *) planstate)->as.nplans, ancestors, es); break; case T_BitmapAnd: @@ -2609,7 +2609,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 132fe37ef60..044e871622d 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -911,8 +911,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)) { @@ -924,8 +924,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 85c85569b5e..272bf52fc2d 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -127,9 +127,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; @@ -137,7 +137,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; @@ -146,12 +146,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); /* @@ -161,23 +161,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 * @@ -196,7 +196,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 @@ -219,8 +219,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 @@ -234,30 +234,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; @@ -273,13 +273,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); } @@ -287,7 +287,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; @@ -317,11 +317,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); /* @@ -329,11 +329,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; @@ -348,19 +348,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 @@ -387,7 +387,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); } } @@ -409,8 +409,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 @@ -422,7 +422,7 @@ ExecEndAppend(AppendState *node) void ExecReScanAppend(AppendState *node) { - int nasyncplans = node->as_nasyncplans; + int nasyncplans = node->as.nasyncplans; int i; /* @@ -430,27 +430,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 @@ -464,9 +464,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]; areq->callback_pending = false; areq->request_complete = false; @@ -475,8 +475,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 */ @@ -503,7 +503,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); @@ -525,7 +525,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; @@ -543,7 +543,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); } /* ---------------------------------------------------------------- @@ -556,7 +556,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; } @@ -574,7 +574,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) @@ -589,33 +589,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; } @@ -639,10 +639,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); @@ -654,18 +654,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 @@ -721,10 +721,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); @@ -737,11 +737,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); } @@ -761,7 +761,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) { @@ -774,7 +774,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; @@ -799,7 +799,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); /* @@ -808,7 +808,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) @@ -850,16 +850,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; } } @@ -881,27 +881,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) @@ -909,9 +909,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); Assert(!areq->callback_pending); @@ -963,7 +963,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; } @@ -983,7 +983,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; @@ -996,17 +996,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); @@ -1017,7 +1017,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; } @@ -1033,7 +1033,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; @@ -1042,16 +1042,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); @@ -1061,10 +1061,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; } @@ -1080,7 +1080,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. */ @@ -1091,10 +1091,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; @@ -1167,14 +1167,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); } @@ -1191,11 +1191,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; @@ -1203,20 +1203,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 72eebd50bdf..d7d2de08147 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -79,12 +79,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; @@ -93,12 +93,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); /* @@ -107,25 +107,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, @@ -139,7 +139,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); } @@ -156,20 +156,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 @@ -224,26 +224,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)); } @@ -261,7 +261,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 @@ -271,7 +271,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 { @@ -342,8 +342,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 @@ -362,24 +362,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 c0b880ec233..5cb9d55f2e4 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -4858,14 +4858,14 @@ planstate_tree_walker_impl(PlanState *planstate, switch (nodeTag(plan)) { case T_Append: - if (planstate_walk_members(((AppendState *) planstate)->appendplans, - ((AppendState *) planstate)->as_nplans, + if (planstate_walk_members(((AppendState *) planstate)->as.plans, + ((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(((MergeAppendState *) planstate)->as.plans, + ((MergeAppendState *) planstate)->as.nplans, walker, context)) return true; break; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 150289613cd..c088b0b3c71 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..af7ceccb8ad 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1881,10 +1881,10 @@ set_append_references(PlannerInfo *root, * 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(aplan->ab.plan.qual == NIL); /* First, we gotta recurse on the children */ - foreach(l, aplan->appendplans) + foreach(l, aplan->ab.subplans) { lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -1897,11 +1897,11 @@ set_append_references(PlannerInfo *root, * plan may execute the non-parallel aware child multiple times. (If you * change these rules, update create_append_path to match.) */ - if (list_length(aplan->appendplans) == 1) + if (list_length(aplan->ab.subplans) == 1) { - Plan *p = (Plan *) linitial(aplan->appendplans); + Plan *p = (Plan *) linitial(aplan->ab.subplans); - if (p->parallel_aware == aplan->plan.parallel_aware) + if (p->parallel_aware == aplan->ab.plan.parallel_aware) { Plan *result; @@ -1909,7 +1909,7 @@ set_append_references(PlannerInfo *root, /* Remember that we removed an Append */ record_elided_node(root->glob, p->plan_node_id, T_Append, - offset_relid_set(aplan->apprelids, rtoffset)); + offset_relid_set(aplan->ab.apprelids, rtoffset)); return result; } @@ -1922,19 +1922,19 @@ set_append_references(PlannerInfo *root, */ set_dummy_tlist_references((Plan *) aplan, rtoffset); - aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset); + aplan->ab.apprelids = offset_relid_set(aplan->ab.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); + if (aplan->ab.part_prune_index >= 0) + aplan->ab.part_prune_index = + register_partpruneinfo(root, aplan->ab.part_prune_index, rtoffset); /* We don't need to recurse to lefttree or righttree ... */ - Assert(aplan->plan.lefttree == NULL); - Assert(aplan->plan.righttree == NULL); + Assert(aplan->ab.plan.lefttree == NULL); + Assert(aplan->ab.plan.righttree == NULL); return (Plan *) aplan; } @@ -1958,10 +1958,10 @@ set_mergeappend_references(PlannerInfo *root, * 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); + Assert(mplan->ab.plan.qual == NIL); /* First, we gotta recurse on the children */ - foreach(l, mplan->mergeplans) + foreach(l, mplan->ab.subplans) { lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -1975,11 +1975,11 @@ set_mergeappend_references(PlannerInfo *root, * multiple times. (If you change these rules, update * create_merge_append_path to match.) */ - if (list_length(mplan->mergeplans) == 1) + if (list_length(mplan->ab.subplans) == 1) { - Plan *p = (Plan *) linitial(mplan->mergeplans); + Plan *p = (Plan *) linitial(mplan->ab.subplans); - if (p->parallel_aware == mplan->plan.parallel_aware) + if (p->parallel_aware == mplan->ab.plan.parallel_aware) { Plan *result; @@ -1987,7 +1987,7 @@ set_mergeappend_references(PlannerInfo *root, /* Remember that we removed a MergeAppend */ record_elided_node(root->glob, p->plan_node_id, T_MergeAppend, - offset_relid_set(mplan->apprelids, rtoffset)); + offset_relid_set(mplan->ab.apprelids, rtoffset)); return result; } @@ -2000,19 +2000,19 @@ set_mergeappend_references(PlannerInfo *root, */ set_dummy_tlist_references((Plan *) mplan, rtoffset); - mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset); + mplan->ab.apprelids = offset_relid_set(mplan->ab.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 (mplan->ab.part_prune_index >= 0) + mplan->ab.part_prune_index = + register_partpruneinfo(root, mplan->ab.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(mplan->ab.plan.lefttree == NULL); + Assert(mplan->ab.plan.righttree == NULL); return (Plan *) mplan; } diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index ccec1eaa7fe..e21eb0f8725 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2904,7 +2904,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, @@ -2919,7 +2919,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 35083fcc733..a6e7826d852 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 3ecae7552fc..423e5ecfa33 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1510,6 +1510,39 @@ typedef struct ModifyTableState List *mt_mergeJoinConditions; } 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 * @@ -1531,30 +1564,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 *); }; @@ -1575,16 +1599,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 7515682fe9f..8faf300b02d 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)