diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 19 | ||||
-rw-r--r-- | src/backend/executor/execParallel.c | 1 | ||||
-rw-r--r-- | src/backend/executor/execPartition.c | 83 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 12 | ||||
-rw-r--r-- | src/backend/executor/nodeAppend.c | 8 | ||||
-rw-r--r-- | src/backend/executor/nodeLockRows.c | 9 | ||||
-rw-r--r-- | src/backend/executor/nodeMergeAppend.c | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 70 |
8 files changed, 171 insertions, 33 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 604cb0625b8..74ef35cd250 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -851,7 +851,8 @@ InitPlan(QueryDesc *queryDesc, int eflags) /* * initialize the node's execution state */ - ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos); + ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos, + bms_copy(plannedstmt->unprunableRelids)); estate->es_plannedstmt = plannedstmt; estate->es_part_prune_infos = plannedstmt->partPruneInfos; @@ -881,8 +882,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) Relation relation; ExecRowMark *erm; - /* ignore "parent" rowmarks; they are irrelevant at runtime */ - if (rc->isParent) + /* + * Ignore "parent" rowmarks, because they are irrelevant at + * runtime. Also ignore the rowmarks belonging to child tables + * that have been pruned in ExecDoInitialPruning(). + */ + if (rc->isParent || + !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; /* get relation's OID (will produce InvalidOid if subquery) */ @@ -2934,6 +2940,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) } /* + * Copy es_unpruned_relids so that pruned relations are ignored by + * ExecInitLockRows() and ExecInitModifyTable() when initializing the plan + * trees below. + */ + rcestate->es_unpruned_relids = parentestate->es_unpruned_relids; + + /* * Initialize private state information for each SubPlan. We must do this * before running ExecInitNode on the main query tree, since * ExecInitSubPlan expects to be able to find these entries. Some of the diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 9c313d81315..134ff62f5cb 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -183,6 +183,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->planTree = plan; pstmt->partPruneInfos = estate->es_part_prune_infos; pstmt->rtable = estate->es_range_table; + pstmt->unprunableRelids = estate->es_unpruned_relids; pstmt->permInfos = estate->es_rteperminfos; pstmt->resultRelations = NIL; pstmt->appendRelations = NIL; diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 57245349cec..b6e89d0620d 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -182,7 +182,8 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel, static List *adjust_partition_colnos(List *colnos, ResultRelInfo *leaf_part_rri); static List *adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap); static PartitionPruneState *CreatePartitionPruneState(EState *estate, - PartitionPruneInfo *pruneinfo); + PartitionPruneInfo *pruneinfo, + Bitmapset **all_leafpart_rtis); static void InitPartitionPruneContext(PartitionPruneContext *context, List *pruning_steps, PartitionDesc partdesc, @@ -196,7 +197,8 @@ static void InitExecPartitionPruneContexts(PartitionPruneState *prunstate, static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, - Bitmapset **validsubplans); + Bitmapset **validsubplans, + Bitmapset **validsubplan_rtis); /* @@ -1820,9 +1822,12 @@ ExecDoInitialPruning(EState *estate) PartitionPruneInfo *pruneinfo = lfirst_node(PartitionPruneInfo, lc); PartitionPruneState *prunestate; Bitmapset *validsubplans = NULL; + Bitmapset *all_leafpart_rtis = NULL; + Bitmapset *validsubplan_rtis = NULL; /* Create and save the PartitionPruneState. */ - prunestate = CreatePartitionPruneState(estate, pruneinfo); + prunestate = CreatePartitionPruneState(estate, pruneinfo, + &all_leafpart_rtis); estate->es_part_prune_states = lappend(estate->es_part_prune_states, prunestate); @@ -1831,7 +1836,13 @@ ExecDoInitialPruning(EState *estate) * bitmapset or NULL as described in the header comment. */ if (prunestate->do_initial_prune) - validsubplans = ExecFindMatchingSubPlans(prunestate, true); + validsubplans = ExecFindMatchingSubPlans(prunestate, true, + &validsubplan_rtis); + else + validsubplan_rtis = all_leafpart_rtis; + + estate->es_unpruned_relids = bms_add_members(estate->es_unpruned_relids, + validsubplan_rtis); estate->es_part_prune_results = lappend(estate->es_part_prune_results, validsubplans); } @@ -1944,9 +1955,16 @@ ExecInitPartitionExecPruning(PlanState *planstate, * initialized here. Those required for exec pruning are initialized later in * ExecInitPartitionExecPruning(), as they depend on the availability of the * parent plan node's PlanState. + * + * If initial pruning steps are to be skipped (e.g., during EXPLAIN + * (GENERIC_PLAN)), *all_leafpart_rtis will be populated with the RT indexes of + * all leaf partitions whose scanning subnode is included in the parent plan + * node's list of child plans. The caller must add these RT indexes to + * estate->es_unpruned_relids. */ static PartitionPruneState * -CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) +CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo, + Bitmapset **all_leafpart_rtis) { PartitionPruneState *prunestate; int n_part_hierarchies; @@ -2039,8 +2057,8 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) * The set of partitions that exist now might not be the same that * existed when the plan was made. The normal case is that it is; * optimize for that case with a quick comparison, and just copy - * the subplan_map and make subpart_map point to the one in - * PruneInfo. + * the subplan_map and make subpart_map, leafpart_rti_map point to + * the ones in PruneInfo. * * For the case where they aren't identical, we could have more * partitions on either side; or even exactly the same number of @@ -2059,6 +2077,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) sizeof(int) * partdesc->nparts) == 0) { pprune->subpart_map = pinfo->subpart_map; + pprune->leafpart_rti_map = pinfo->leafpart_rti_map; memcpy(pprune->subplan_map, pinfo->subplan_map, sizeof(int) * pinfo->nparts); } @@ -2079,6 +2098,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) * mismatches. */ pprune->subpart_map = palloc(sizeof(int) * partdesc->nparts); + pprune->leafpart_rti_map = palloc(sizeof(int) * partdesc->nparts); for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++) { @@ -2096,6 +2116,8 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) pinfo->subplan_map[pd_idx]; pprune->subpart_map[pp_idx] = pinfo->subpart_map[pd_idx]; + pprune->leafpart_rti_map[pp_idx] = + pinfo->leafpart_rti_map[pd_idx]; pd_idx++; continue; } @@ -2133,6 +2155,7 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) pprune->subpart_map[pp_idx] = -1; pprune->subplan_map[pp_idx] = -1; + pprune->leafpart_rti_map[pp_idx] = 0; } } @@ -2174,6 +2197,25 @@ CreatePartitionPruneState(EState *estate, PartitionPruneInfo *pruneinfo) prunestate->execparamids = bms_add_members(prunestate->execparamids, pinfo->execparamids); + /* + * Return all leaf partition indexes if we're skipping pruning in + * the EXPLAIN (GENERIC_PLAN) case. + */ + if (pinfo->initial_pruning_steps && !prunestate->do_initial_prune) + { + int part_index = -1; + + while ((part_index = bms_next_member(pprune->present_parts, + part_index)) >= 0) + { + Index rtindex = pprune->leafpart_rti_map[part_index]; + + if (rtindex) + *all_leafpart_rtis = bms_add_member(*all_leafpart_rtis, + rtindex); + } + } + j++; } i++; @@ -2439,10 +2481,15 @@ InitExecPartitionPruneContexts(PartitionPruneState *prunestate, * Pass initial_prune if PARAM_EXEC Params cannot yet be evaluated. This * differentiates the initial executor-time pruning step from later * runtime pruning. + * + * The caller must pass a non-NULL validsubplan_rtis during initial pruning + * to collect the RT indexes of leaf partitions whose subnodes will be + * executed. These RT indexes are later added to EState.es_unpruned_relids. */ Bitmapset * ExecFindMatchingSubPlans(PartitionPruneState *prunestate, - bool initial_prune) + bool initial_prune, + Bitmapset **validsubplan_rtis) { Bitmapset *result = NULL; MemoryContext oldcontext; @@ -2454,6 +2501,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate, * evaluated *and* there are steps in which to do so. */ Assert(initial_prune || prunestate->do_exec_prune); + Assert(validsubplan_rtis != NULL || !initial_prune); /* * Switch to a temp context to avoid leaking memory in the executor's @@ -2477,7 +2525,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate, */ pprune = &prunedata->partrelprunedata[0]; find_matching_subplans_recurse(prunedata, pprune, initial_prune, - &result); + &result, validsubplan_rtis); /* * Expression eval may have used space in ExprContext too. Avoid @@ -2495,6 +2543,8 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate, /* Copy result out of the temp context before we reset it */ result = bms_copy(result); + if (validsubplan_rtis) + *validsubplan_rtis = bms_copy(*validsubplan_rtis); MemoryContextReset(prunestate->prune_context); @@ -2505,13 +2555,16 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate, * find_matching_subplans_recurse * Recursive worker function for ExecFindMatchingSubPlans * - * Adds valid (non-prunable) subplan IDs to *validsubplans + * Adds valid (non-prunable) subplan IDs to *validsubplans and the RT indexes + * of their corresponding leaf partitions to *validsubplan_rtis if + * it's non-NULL. */ static void find_matching_subplans_recurse(PartitionPruningData *prunedata, PartitionedRelPruningData *pprune, bool initial_prune, - Bitmapset **validsubplans) + Bitmapset **validsubplans, + Bitmapset **validsubplan_rtis) { Bitmapset *partset; int i; @@ -2538,8 +2591,13 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata, while ((i = bms_next_member(partset, i)) >= 0) { if (pprune->subplan_map[i] >= 0) + { *validsubplans = bms_add_member(*validsubplans, pprune->subplan_map[i]); + if (validsubplan_rtis) + *validsubplan_rtis = bms_add_member(*validsubplan_rtis, + pprune->leafpart_rti_map[i]); + } else { int partidx = pprune->subpart_map[i]; @@ -2547,7 +2605,8 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata, if (partidx >= 0) find_matching_subplans_recurse(prunedata, &prunedata->partrelprunedata[partidx], - initial_prune, validsubplans); + initial_prune, validsubplans, + validsubplan_rtis); else { /* diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 00564985668..c9c756f8568 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -771,7 +771,8 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags) * indexed by rangetable index. */ void -ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos) +ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos, + Bitmapset *unpruned_relids) { /* Remember the range table List as-is */ estate->es_range_table = rangeTable; @@ -783,6 +784,15 @@ ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos) estate->es_range_table_size = list_length(rangeTable); /* + * Initialize the bitmapset of RT indexes (es_unpruned_relids) + * representing relations that will be scanned during execution. This set + * is initially populated by the caller and may be extended later by + * ExecDoInitialPruning() to include RT indexes of unpruned leaf + * partitions. + */ + estate->es_unpruned_relids = unpruned_relids; + + /* * Allocate an array to store an open Relation corresponding to each * rangetable entry, and initialize entries to NULL. Relations are opened * and stored here as needed. diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 2397e5e17b0..15c4227cc62 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -595,7 +595,7 @@ choose_next_subplan_locally(AppendState *node) else if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); node->as_valid_subplans_identified = true; } @@ -662,7 +662,7 @@ choose_next_subplan_for_leader(AppendState *node) if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); node->as_valid_subplans_identified = true; /* @@ -738,7 +738,7 @@ choose_next_subplan_for_worker(AppendState *node) else if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); node->as_valid_subplans_identified = true; mark_invalid_subplans_as_finished(node); @@ -891,7 +891,7 @@ ExecAppendAsyncBegin(AppendState *node) if (!node->as_valid_subplans_identified) { node->as_valid_subplans = - ExecFindMatchingSubPlans(node->as_prune_state, false); + ExecFindMatchingSubPlans(node->as_prune_state, false, NULL); node->as_valid_subplans_identified = true; classify_matching_subplans(node); diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 4e4e3db0b38..a8afbf93b48 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -347,8 +347,13 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) ExecRowMark *erm; ExecAuxRowMark *aerm; - /* ignore "parent" rowmarks; they are irrelevant at runtime */ - if (rc->isParent) + /* + * Ignore "parent" rowmarks, because they are irrelevant at runtime. + * Also ignore the rowmarks belonging to child tables that have been + * pruned in ExecDoInitialPruning(). + */ + if (rc->isParent || + !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; /* find ExecRowMark and build ExecAuxRowMark */ diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index b2dc6626c99..405e8f94285 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -233,7 +233,7 @@ ExecMergeAppend(PlanState *pstate) */ if (node->ms_valid_subplans == NULL) node->ms_valid_subplans = - ExecFindMatchingSubPlans(node->ms_prune_state, false); + ExecFindMatchingSubPlans(node->ms_prune_state, false, NULL); /* * First time through: pull the first tuple from each valid subplan, diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index bc82e035ba2..349ed2d6d2c 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -690,7 +690,7 @@ ExecInitUpdateProjection(ModifyTableState *mtstate, Assert(whichrel >= 0 && whichrel < mtstate->mt_nrels); } - updateColnos = (List *) list_nth(node->updateColnosLists, whichrel); + updateColnos = (List *) list_nth(mtstate->mt_updateColnosLists, whichrel); /* * For UPDATE, we use the old tuple to fill up missing values in the tuple @@ -4453,7 +4453,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ModifyTableState *mtstate; Plan *subplan = outerPlan(node); CmdType operation = node->operation; - int nrels = list_length(node->resultRelations); + int nrels; + List *resultRelations = NIL; + List *withCheckOptionLists = NIL; + List *returningLists = NIL; + List *updateColnosLists = NIL; ResultRelInfo *resultRelInfo; List *arowmarks; ListCell *l; @@ -4464,6 +4468,45 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); /* + * Only consider unpruned relations for initializing their ResultRelInfo + * struct and other fields such as withCheckOptions, etc. + */ + i = 0; + foreach(l, node->resultRelations) + { + Index rti = lfirst_int(l); + + if (bms_is_member(rti, estate->es_unpruned_relids)) + { + resultRelations = lappend_int(resultRelations, rti); + if (node->withCheckOptionLists) + { + List *withCheckOptions = list_nth_node(List, + node->withCheckOptionLists, + i); + + withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions); + } + if (node->returningLists) + { + List *returningList = list_nth_node(List, + node->returningLists, + i); + + returningLists = lappend(returningLists, returningList); + } + if (node->updateColnosLists) + { + List *updateColnosList = list_nth(node->updateColnosLists, i); + + updateColnosLists = lappend(updateColnosLists, updateColnosList); + } + } + i++; + } + nrels = list_length(resultRelations); + + /* * create state structure */ mtstate = makeNode(ModifyTableState); @@ -4483,6 +4526,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->mt_merge_inserted = 0; mtstate->mt_merge_updated = 0; mtstate->mt_merge_deleted = 0; + mtstate->mt_updateColnosLists = updateColnosLists; /*---------- * Resolve the target relation. This is the same as: @@ -4500,6 +4544,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) */ if (node->rootRelation > 0) { + Assert(bms_is_member(node->rootRelation, estate->es_unpruned_relids)); mtstate->rootResultRelInfo = makeNode(ResultRelInfo); ExecInitResultRelation(estate, mtstate->rootResultRelInfo, node->rootRelation); @@ -4514,7 +4559,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* set up epqstate with dummy subplan data for the moment */ EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, - node->epqParam, node->resultRelations); + node->epqParam, resultRelations); mtstate->fireBSTriggers = true; /* @@ -4532,7 +4577,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) */ resultRelInfo = mtstate->resultRelInfo; i = 0; - foreach(l, node->resultRelations) + foreach(l, resultRelations) { Index resultRelation = lfirst_int(l); List *mergeActions = NIL; @@ -4676,7 +4721,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Initialize any WITH CHECK OPTION constraints if needed. */ resultRelInfo = mtstate->resultRelInfo; - foreach(l, node->withCheckOptionLists) + foreach(l, withCheckOptionLists) { List *wcoList = (List *) lfirst(l); List *wcoExprs = NIL; @@ -4699,7 +4744,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* * Initialize RETURNING projections if needed. */ - if (node->returningLists) + if (returningLists) { TupleTableSlot *slot; ExprContext *econtext; @@ -4708,7 +4753,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Initialize result tuple slot and assign its rowtype using the first * RETURNING list. We assume the rest will look the same. */ - mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists); + mtstate->ps.plan->targetlist = (List *) linitial(returningLists); /* Set up a slot for the output of the RETURNING projection(s) */ ExecInitResultTupleSlotTL(&mtstate->ps, &TTSOpsVirtual); @@ -4723,7 +4768,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Build a projection for each result rel. */ resultRelInfo = mtstate->resultRelInfo; - foreach(l, node->returningLists) + foreach(l, returningLists) { List *rlist = (List *) lfirst(l); @@ -4824,8 +4869,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ExecRowMark *erm; ExecAuxRowMark *aerm; - /* ignore "parent" rowmarks; they are irrelevant at runtime */ - if (rc->isParent) + /* + * Ignore "parent" rowmarks, because they are irrelevant at runtime. + * Also ignore the rowmarks belonging to child tables that have been + * pruned in ExecDoInitialPruning(). + */ + if (rc->isParent || + !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; /* Find ExecRowMark and build ExecAuxRowMark */ |