Skip to content

Commit bb3ec16

Browse files
committed
Move PartitionPruneInfo out of plan nodes into PlannedStmt
This moves PartitionPruneInfo from plan nodes to PlannedStmt, simplifying traversal by centralizing all PartitionPruneInfo structures in a single list in it, which holds all instances for the main query and its subqueries. Instead of plan nodes (Append or MergeAppend) storing PartitionPruneInfo pointers, they now reference an index in this list. A bitmapset field is added to PartitionPruneInfo to store the RT indexes corresponding to the apprelids field in Append or MergeAppend. This allows execution pruning logic to verify that it operates on the correct plan node, mainly to facilitate debugging. Duplicated code in set_append_references() and set_mergeappend_references() is refactored into a new function, register_pruneinfo(). This updates RT indexes by applying rtoffet and adds PartitionPruneInfo to the global list in PlannerGlobal. By allowing pruning to be performed without traversing the plan tree, this change lays the groundwork for runtime initial pruning to occur independently of plan tree initialization. Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> (earlier version) Reviewed-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Tomas Vondra <tomas@vondra.me> Discussion: https://postgr.es/m/CA+HiwqFGkMSge6TgC9KQzde0ohpAycLQuV7ooitEEpbKB0O_mg@mail.gmail.com
1 parent ba0da16 commit bb3ec16

File tree

15 files changed

+137
-73
lines changed

15 files changed

+137
-73
lines changed

src/backend/executor/execMain.c

+1
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
853853
ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos);
854854

855855
estate->es_plannedstmt = plannedstmt;
856+
estate->es_part_prune_infos = plannedstmt->partPruneInfos;
856857

857858
/*
858859
* Next, build the ExecRowMark array from the PlanRowMark(s), if any.

src/backend/executor/execParallel.c

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
181181
pstmt->dependsOnRole = false;
182182
pstmt->parallelModeNeeded = false;
183183
pstmt->planTree = plan;
184+
pstmt->partPruneInfos = estate->es_part_prune_infos;
184185
pstmt->rtable = estate->es_range_table;
185186
pstmt->permInfos = estate->es_rteperminfos;
186187
pstmt->resultRelations = NIL;

src/backend/executor/execPartition.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,9 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap)
17861786
* Initialize data structure needed for run-time partition pruning and
17871787
* do initial pruning if needed
17881788
*
1789+
* 'relids' identifies the relation to which both the parent plan and the
1790+
* PartitionPruneInfo given by 'part_prune_index' belong.
1791+
*
17891792
* On return, *initially_valid_subplans is assigned the set of indexes of
17901793
* child subplans that must be initialized along with the parent plan node.
17911794
* Initial pruning is performed here if needed and in that case only the
@@ -1798,11 +1801,23 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap)
17981801
PartitionPruneState *
17991802
ExecInitPartitionPruning(PlanState *planstate,
18001803
int n_total_subplans,
1801-
PartitionPruneInfo *pruneinfo,
1804+
int part_prune_index,
1805+
Bitmapset *relids,
18021806
Bitmapset **initially_valid_subplans)
18031807
{
18041808
PartitionPruneState *prunestate;
18051809
EState *estate = planstate->state;
1810+
PartitionPruneInfo *pruneinfo;
1811+
1812+
/* Obtain the pruneinfo we need. */
1813+
pruneinfo = list_nth_node(PartitionPruneInfo, estate->es_part_prune_infos,
1814+
part_prune_index);
1815+
1816+
/* Its relids better match the plan node's or the planner messed up. */
1817+
if (!bms_equal(relids, pruneinfo->relids))
1818+
elog(ERROR, "wrong pruneinfo with relids=%s found at part_prune_index=%d contained in plan node with relids=%s",
1819+
bmsToString(pruneinfo->relids), part_prune_index,
1820+
bmsToString(relids));
18061821

18071822
/* We may need an expression context to evaluate partition exprs */
18081823
ExecAssignExprContext(estate, planstate);

src/backend/executor/execUtils.c

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ CreateExecutorState(void)
118118
estate->es_rowmarks = NULL;
119119
estate->es_rteperminfos = NIL;
120120
estate->es_plannedstmt = NULL;
121+
estate->es_part_prune_infos = NIL;
121122

122123
estate->es_junkFilter = NULL;
123124

src/backend/executor/nodeAppend.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
135135
appendstate->as_begun = false;
136136

137137
/* If run-time partition pruning is enabled, then set that up now */
138-
if (node->part_prune_info != NULL)
138+
if (node->part_prune_index >= 0)
139139
{
140140
PartitionPruneState *prunestate;
141141

@@ -146,7 +146,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
146146
*/
147147
prunestate = ExecInitPartitionPruning(&appendstate->ps,
148148
list_length(node->appendplans),
149-
node->part_prune_info,
149+
node->part_prune_index,
150+
node->apprelids,
150151
&validsubplans);
151152
appendstate->as_prune_state = prunestate;
152153
nplans = bms_num_members(validsubplans);

src/backend/executor/nodeMergeAppend.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
8383
mergestate->ps.ExecProcNode = ExecMergeAppend;
8484

8585
/* If run-time partition pruning is enabled, then set that up now */
86-
if (node->part_prune_info != NULL)
86+
if (node->part_prune_index >= 0)
8787
{
8888
PartitionPruneState *prunestate;
8989

@@ -94,7 +94,8 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
9494
*/
9595
prunestate = ExecInitPartitionPruning(&mergestate->ps,
9696
list_length(node->mergeplans),
97-
node->part_prune_info,
97+
node->part_prune_index,
98+
node->apprelids,
9899
&validsubplans);
99100
mergestate->ms_prune_state = prunestate;
100101
nplans = bms_num_members(validsubplans);

src/backend/optimizer/plan/createplan.c

+12-11
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
12271227
ListCell *subpaths;
12281228
int nasyncplans = 0;
12291229
RelOptInfo *rel = best_path->path.parent;
1230-
PartitionPruneInfo *partpruneinfo = NULL;
12311230
int nodenumsortkeys = 0;
12321231
AttrNumber *nodeSortColIdx = NULL;
12331232
Oid *nodeSortOperators = NULL;
@@ -1378,6 +1377,9 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
13781377
subplans = lappend(subplans, subplan);
13791378
}
13801379

1380+
/* Set below if we find quals that we can use to run-time prune */
1381+
plan->part_prune_index = -1;
1382+
13811383
/*
13821384
* If any quals exist, they may be useful to perform further partition
13831385
* pruning during execution. Gather information needed by the executor to
@@ -1401,16 +1403,14 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
14011403
}
14021404

14031405
if (prunequal != NIL)
1404-
partpruneinfo =
1405-
make_partition_pruneinfo(root, rel,
1406-
best_path->subpaths,
1407-
prunequal);
1406+
plan->part_prune_index = make_partition_pruneinfo(root, rel,
1407+
best_path->subpaths,
1408+
prunequal);
14081409
}
14091410

14101411
plan->appendplans = subplans;
14111412
plan->nasyncplans = nasyncplans;
14121413
plan->first_partial_plan = best_path->first_partial_path;
1413-
plan->part_prune_info = partpruneinfo;
14141414

14151415
copy_generic_path_info(&plan->plan, (Path *) best_path);
14161416

@@ -1449,7 +1449,6 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
14491449
List *subplans = NIL;
14501450
ListCell *subpaths;
14511451
RelOptInfo *rel = best_path->path.parent;
1452-
PartitionPruneInfo *partpruneinfo = NULL;
14531452

14541453
/*
14551454
* We don't have the actual creation of the MergeAppend node split out
@@ -1542,6 +1541,9 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
15421541
subplans = lappend(subplans, subplan);
15431542
}
15441543

1544+
/* Set below if we find quals that we can use to run-time prune */
1545+
node->part_prune_index = -1;
1546+
15451547
/*
15461548
* If any quals exist, they may be useful to perform further partition
15471549
* pruning during execution. Gather information needed by the executor to
@@ -1557,13 +1559,12 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
15571559
Assert(best_path->path.param_info == NULL);
15581560

15591561
if (prunequal != NIL)
1560-
partpruneinfo = make_partition_pruneinfo(root, rel,
1561-
best_path->subpaths,
1562-
prunequal);
1562+
node->part_prune_index = make_partition_pruneinfo(root, rel,
1563+
best_path->subpaths,
1564+
prunequal);
15631565
}
15641566

15651567
node->mergeplans = subplans;
1566-
node->part_prune_info = partpruneinfo;
15671568

15681569
/*
15691570
* If prepare_sort_from_pathkeys added sort columns, but we were told to

src/backend/optimizer/plan/planner.c

+1
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
555555
result->dependsOnRole = glob->dependsOnRole;
556556
result->parallelModeNeeded = glob->parallelModeNeeded;
557557
result->planTree = top_plan;
558+
result->partPruneInfos = glob->partPruneInfos;
558559
result->rtable = glob->finalrtable;
559560
result->permInfos = glob->finalrteperminfos;
560561
result->resultRelations = glob->resultRelations;

src/backend/optimizer/plan/setrefs.c

+61-42
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,53 @@ set_customscan_references(PlannerInfo *root,
17311731
cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset);
17321732
}
17331733

1734+
/*
1735+
* register_partpruneinfo
1736+
* Subroutine for set_append_references and set_mergeappend_references
1737+
*
1738+
* Add the PartitionPruneInfo from root->partPruneInfos at the given index
1739+
* into PlannerGlobal->partPruneInfos and return its index there.
1740+
*
1741+
* Also update the RT indexes present in PartitionedRelPruneInfos to add the
1742+
* offset.
1743+
*/
1744+
static int
1745+
register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
1746+
{
1747+
PlannerGlobal *glob = root->glob;
1748+
PartitionPruneInfo *pinfo;
1749+
ListCell *l;
1750+
1751+
Assert(part_prune_index >= 0 &&
1752+
part_prune_index < list_length(root->partPruneInfos));
1753+
pinfo = list_nth_node(PartitionPruneInfo, root->partPruneInfos,
1754+
part_prune_index);
1755+
1756+
pinfo->relids = offset_relid_set(pinfo->relids, rtoffset);
1757+
foreach(l, pinfo->prune_infos)
1758+
{
1759+
List *prune_infos = lfirst(l);
1760+
ListCell *l2;
1761+
1762+
foreach(l2, prune_infos)
1763+
{
1764+
PartitionedRelPruneInfo *prelinfo = lfirst(l2);
1765+
1766+
prelinfo->rtindex += rtoffset;
1767+
prelinfo->initial_pruning_steps =
1768+
fix_scan_list(root, prelinfo->initial_pruning_steps,
1769+
rtoffset, 1);
1770+
prelinfo->exec_pruning_steps =
1771+
fix_scan_list(root, prelinfo->exec_pruning_steps,
1772+
rtoffset, 1);
1773+
}
1774+
}
1775+
1776+
glob->partPruneInfos = lappend(glob->partPruneInfos, pinfo);
1777+
1778+
return list_length(glob->partPruneInfos) - 1;
1779+
}
1780+
17341781
/*
17351782
* set_append_references
17361783
* Do set_plan_references processing on an Append
@@ -1783,27 +1830,13 @@ set_append_references(PlannerInfo *root,
17831830

17841831
aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset);
17851832

1786-
if (aplan->part_prune_info)
1787-
{
1788-
foreach(l, aplan->part_prune_info->prune_infos)
1789-
{
1790-
List *prune_infos = lfirst(l);
1791-
ListCell *l2;
1792-
1793-
foreach(l2, prune_infos)
1794-
{
1795-
PartitionedRelPruneInfo *pinfo = lfirst(l2);
1796-
1797-
pinfo->rtindex += rtoffset;
1798-
pinfo->initial_pruning_steps =
1799-
fix_scan_list(root, pinfo->initial_pruning_steps,
1800-
rtoffset, 1);
1801-
pinfo->exec_pruning_steps =
1802-
fix_scan_list(root, pinfo->exec_pruning_steps,
1803-
rtoffset, 1);
1804-
}
1805-
}
1806-
}
1833+
/*
1834+
* Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
1835+
* Also update the RT indexes present in it to add the offset.
1836+
*/
1837+
if (aplan->part_prune_index >= 0)
1838+
aplan->part_prune_index =
1839+
register_partpruneinfo(root, aplan->part_prune_index, rtoffset);
18071840

18081841
/* We don't need to recurse to lefttree or righttree ... */
18091842
Assert(aplan->plan.lefttree == NULL);
@@ -1865,27 +1898,13 @@ set_mergeappend_references(PlannerInfo *root,
18651898

18661899
mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset);
18671900

1868-
if (mplan->part_prune_info)
1869-
{
1870-
foreach(l, mplan->part_prune_info->prune_infos)
1871-
{
1872-
List *prune_infos = lfirst(l);
1873-
ListCell *l2;
1874-
1875-
foreach(l2, prune_infos)
1876-
{
1877-
PartitionedRelPruneInfo *pinfo = lfirst(l2);
1878-
1879-
pinfo->rtindex += rtoffset;
1880-
pinfo->initial_pruning_steps =
1881-
fix_scan_list(root, pinfo->initial_pruning_steps,
1882-
rtoffset, 1);
1883-
pinfo->exec_pruning_steps =
1884-
fix_scan_list(root, pinfo->exec_pruning_steps,
1885-
rtoffset, 1);
1886-
}
1887-
}
1888-
}
1901+
/*
1902+
* Add PartitionPruneInfo, if any, to PlannerGlobal and update the index.
1903+
* Also update the RT indexes present in it to add the offset.
1904+
*/
1905+
if (mplan->part_prune_index >= 0)
1906+
mplan->part_prune_index =
1907+
register_partpruneinfo(root, mplan->part_prune_index, rtoffset);
18891908

18901909
/* We don't need to recurse to lefttree or righttree ... */
18911910
Assert(mplan->plan.lefttree == NULL);

src/backend/partitioning/partprune.c

+13-6
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,20 @@ static void partkey_datum_from_expr(PartitionPruneContext *context,
207207

208208
/*
209209
* make_partition_pruneinfo
210-
* Builds a PartitionPruneInfo which can be used in the executor to allow
211-
* additional partition pruning to take place. Returns NULL when
212-
* partition pruning would be useless.
210+
* Checks if the given set of quals can be used to build pruning steps
211+
* that the executor can use to prune away unneeded partitions. If
212+
* suitable quals are found then a PartitionPruneInfo is built and tagged
213+
* onto the PlannerInfo's partPruneInfos list.
214+
*
215+
* The return value is the 0-based index of the item added to the
216+
* partPruneInfos list or -1 if nothing was added.
213217
*
214218
* 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list
215219
* of scan paths for its child rels.
216220
* 'prunequal' is a list of potential pruning quals (i.e., restriction
217221
* clauses that are applicable to the appendrel).
218222
*/
219-
PartitionPruneInfo *
223+
int
220224
make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
221225
List *subpaths,
222226
List *prunequal)
@@ -330,10 +334,11 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
330334
* quals, then we can just not bother with run-time pruning.
331335
*/
332336
if (prunerelinfos == NIL)
333-
return NULL;
337+
return -1;
334338

335339
/* Else build the result data structure */
336340
pruneinfo = makeNode(PartitionPruneInfo);
341+
pruneinfo->relids = bms_copy(parentrel->relids);
337342
pruneinfo->prune_infos = prunerelinfos;
338343

339344
/*
@@ -356,7 +361,9 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
356361
else
357362
pruneinfo->other_subplans = NULL;
358363

359-
return pruneinfo;
364+
root->partPruneInfos = lappend(root->partPruneInfos, pruneinfo);
365+
366+
return list_length(root->partPruneInfos) - 1;
360367
}
361368

362369
/*

src/include/executor/execPartition.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ typedef struct PartitionPruneState
123123

124124
extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate,
125125
int n_total_subplans,
126-
PartitionPruneInfo *pruneinfo,
126+
int part_prune_index,
127+
Bitmapset *relids,
127128
Bitmapset **initially_valid_subplans);
128129
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
129130
bool initial_prune);

src/include/nodes/execnodes.h

+1
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ typedef struct EState
655655
* ExecRowMarks, or NULL if none */
656656
List *es_rteperminfos; /* List of RTEPermissionInfo */
657657
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
658+
List *es_part_prune_infos; /* List of PartitionPruneInfo */
658659
const char *es_sourceText; /* Source text from QueryDesc */
659660

660661
JunkFilter *es_junkFilter; /* top-level junk filter, if any */

src/include/nodes/pathnodes.h

+6
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ typedef struct PlannerGlobal
128128
/* "flat" list of AppendRelInfos */
129129
List *appendRelations;
130130

131+
/* "flat" list of PartitionPruneInfos */
132+
List *partPruneInfos;
133+
131134
/* OIDs of relations the plan depends on */
132135
List *relationOids;
133136

@@ -559,6 +562,9 @@ struct PlannerInfo
559562

560563
/* Does this query modify any partition key columns? */
561564
bool partColsUpdated;
565+
566+
/* PartitionPruneInfos added in this query's plan. */
567+
List *partPruneInfos;
562568
};
563569

564570

0 commit comments

Comments
 (0)