Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6630cca

Browse files
committed
Restructure creation of run-time pruning steps.
Previously, gen_partprune_steps() always built executor pruning steps using all suitable clauses, including those containing PARAM_EXEC Params. This meant that the pruning steps were only completely safe for executor run-time (scan start) pruning. To prune at executor startup, we had to ignore the steps involving exec Params. But this doesn't really work in general, since there may be logic changes needed as well --- for example, pruning according to the last operator's btree strategy is the wrong thing if we're not applying that operator. The rules embodied in gen_partprune_steps() and its minions are sufficiently complicated that tracking their incremental effects in other logic seems quite impractical. Short of a complete redesign, the only safe fix seems to be to run gen_partprune_steps() twice, once to create executor startup pruning steps and then again for run-time pruning steps. We can save a few cycles however by noting during the first scan whether we rejected any clauses because they involved exec Params --- if not, we don't need to do the second scan. In support of this, refactor the internal APIs in partprune.c to make more use of passing information in the GeneratePruningStepsContext struct, rather than as separate arguments. This is, I hope, the last piece of our response to a bug report from Alan Jackson. Back-patch to v11 where this code came in. Discussion: https://postgr.es/m/FAD28A83-AC73-489E-A058-2681FA31D648@tvsquared.com
1 parent 0568589 commit 6630cca

File tree

10 files changed

+614
-484
lines changed

10 files changed

+614
-484
lines changed

src/backend/executor/execPartition.c

+105-75
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
183183
bool *isnull,
184184
int maxfieldlen);
185185
static List *adjust_partition_tlist(List *tlist, TupleConversionMap *map);
186+
static void ExecInitPruningContext(PartitionPruneContext *context,
187+
List *pruning_steps,
188+
PartitionDesc partdesc,
189+
PartitionKey partkey,
190+
PlanState *planstate);
186191
static void find_matching_subplans_recurse(PartitionPruningData *prunedata,
187192
PartitionedRelPruningData *pprune,
188193
bool initial_prune,
@@ -1614,16 +1619,9 @@ ExecCreatePartitionPruneState(PlanState *planstate,
16141619
{
16151620
PartitionedRelPruneInfo *pinfo = lfirst_node(PartitionedRelPruneInfo, lc2);
16161621
PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1617-
PartitionPruneContext *context = &pprune->context;
16181622
Relation partrel;
16191623
PartitionDesc partdesc;
16201624
PartitionKey partkey;
1621-
int partnatts;
1622-
int n_steps;
1623-
ListCell *lc3;
1624-
1625-
/* present_parts is also subject to later modification */
1626-
pprune->present_parts = bms_copy(pinfo->present_parts);
16271625

16281626
/*
16291627
* We can rely on the copies of the partitioned table's partition
@@ -1643,6 +1641,7 @@ ExecCreatePartitionPruneState(PlanState *planstate,
16431641
* However, new partitions may have been added.
16441642
*/
16451643
Assert(partdesc->nparts >= pinfo->nparts);
1644+
pprune->nparts = partdesc->nparts;
16461645
pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
16471646
if (partdesc->nparts == pinfo->nparts)
16481647
{
@@ -1700,66 +1699,30 @@ ExecCreatePartitionPruneState(PlanState *planstate,
17001699
Assert(pd_idx == pinfo->nparts);
17011700
}
17021701

1703-
n_steps = list_length(pinfo->pruning_steps);
1704-
1705-
context->strategy = partkey->strategy;
1706-
context->partnatts = partnatts = partkey->partnatts;
1707-
context->nparts = pinfo->nparts;
1708-
context->boundinfo = partdesc->boundinfo;
1709-
context->partcollation = partkey->partcollation;
1710-
context->partsupfunc = partkey->partsupfunc;
1711-
1712-
/* We'll look up type-specific support functions as needed */
1713-
context->stepcmpfuncs = (FmgrInfo *)
1714-
palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1715-
1716-
context->ppccontext = CurrentMemoryContext;
1717-
context->planstate = planstate;
1702+
/* present_parts is also subject to later modification */
1703+
pprune->present_parts = bms_copy(pinfo->present_parts);
17181704

1719-
/* Initialize expression state for each expression we need */
1720-
context->exprstates = (ExprState **)
1721-
palloc0(sizeof(ExprState *) * n_steps * partnatts);
1722-
foreach(lc3, pinfo->pruning_steps)
1705+
/*
1706+
* Initialize pruning contexts as needed.
1707+
*/
1708+
pprune->initial_pruning_steps = pinfo->initial_pruning_steps;
1709+
if (pinfo->initial_pruning_steps)
17231710
{
1724-
PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc3);
1725-
ListCell *lc4;
1726-
int keyno;
1727-
1728-
/* not needed for other step kinds */
1729-
if (!IsA(step, PartitionPruneStepOp))
1730-
continue;
1731-
1732-
Assert(list_length(step->exprs) <= partnatts);
1733-
1734-
keyno = 0;
1735-
foreach(lc4, step->exprs)
1736-
{
1737-
Expr *expr = (Expr *) lfirst(lc4);
1738-
1739-
/* not needed for Consts */
1740-
if (!IsA(expr, Const))
1741-
{
1742-
int stateidx = PruneCxtStateIdx(partnatts,
1743-
step->step.step_id,
1744-
keyno);
1745-
1746-
context->exprstates[stateidx] =
1747-
ExecInitExpr(expr, context->planstate);
1748-
}
1749-
keyno++;
1750-
}
1711+
ExecInitPruningContext(&pprune->initial_context,
1712+
pinfo->initial_pruning_steps,
1713+
partdesc, partkey, planstate);
1714+
/* Record whether initial pruning is needed at any level */
1715+
prunestate->do_initial_prune = true;
1716+
}
1717+
pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
1718+
if (pinfo->exec_pruning_steps)
1719+
{
1720+
ExecInitPruningContext(&pprune->exec_context,
1721+
pinfo->exec_pruning_steps,
1722+
partdesc, partkey, planstate);
1723+
/* Record whether exec pruning is needed at any level */
1724+
prunestate->do_exec_prune = true;
17511725
}
1752-
1753-
/* Array is not modified at runtime, so just point to plan's copy */
1754-
context->exprhasexecparam = pinfo->hasexecparam;
1755-
1756-
pprune->pruning_steps = pinfo->pruning_steps;
1757-
pprune->do_initial_prune = pinfo->do_initial_prune;
1758-
pprune->do_exec_prune = pinfo->do_exec_prune;
1759-
1760-
/* Record if pruning would be useful at any level */
1761-
prunestate->do_initial_prune |= pinfo->do_initial_prune;
1762-
prunestate->do_exec_prune |= pinfo->do_exec_prune;
17631726

17641727
/*
17651728
* Accumulate the IDs of all PARAM_EXEC Params affecting the
@@ -1776,6 +1739,71 @@ ExecCreatePartitionPruneState(PlanState *planstate,
17761739
return prunestate;
17771740
}
17781741

1742+
/*
1743+
* Initialize a PartitionPruneContext for the given list of pruning steps.
1744+
*/
1745+
static void
1746+
ExecInitPruningContext(PartitionPruneContext *context,
1747+
List *pruning_steps,
1748+
PartitionDesc partdesc,
1749+
PartitionKey partkey,
1750+
PlanState *planstate)
1751+
{
1752+
int n_steps;
1753+
int partnatts;
1754+
ListCell *lc;
1755+
1756+
n_steps = list_length(pruning_steps);
1757+
1758+
context->strategy = partkey->strategy;
1759+
context->partnatts = partnatts = partkey->partnatts;
1760+
context->nparts = partdesc->nparts;
1761+
context->boundinfo = partdesc->boundinfo;
1762+
context->partcollation = partkey->partcollation;
1763+
context->partsupfunc = partkey->partsupfunc;
1764+
1765+
/* We'll look up type-specific support functions as needed */
1766+
context->stepcmpfuncs = (FmgrInfo *)
1767+
palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
1768+
1769+
context->ppccontext = CurrentMemoryContext;
1770+
context->planstate = planstate;
1771+
1772+
/* Initialize expression state for each expression we need */
1773+
context->exprstates = (ExprState **)
1774+
palloc0(sizeof(ExprState *) * n_steps * partnatts);
1775+
foreach(lc, pruning_steps)
1776+
{
1777+
PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc);
1778+
ListCell *lc2;
1779+
int keyno;
1780+
1781+
/* not needed for other step kinds */
1782+
if (!IsA(step, PartitionPruneStepOp))
1783+
continue;
1784+
1785+
Assert(list_length(step->exprs) <= partnatts);
1786+
1787+
keyno = 0;
1788+
foreach(lc2, step->exprs)
1789+
{
1790+
Expr *expr = (Expr *) lfirst(lc2);
1791+
1792+
/* not needed for Consts */
1793+
if (!IsA(expr, Const))
1794+
{
1795+
int stateidx = PruneCxtStateIdx(partnatts,
1796+
step->step.step_id,
1797+
keyno);
1798+
1799+
context->exprstates[stateidx] =
1800+
ExecInitExpr(expr, context->planstate);
1801+
}
1802+
keyno++;
1803+
}
1804+
}
1805+
}
1806+
17791807
/*
17801808
* ExecFindInitialMatchingSubPlans
17811809
* Identify the set of subplans that cannot be eliminated by initial
@@ -1824,7 +1852,8 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
18241852
find_matching_subplans_recurse(prunedata, pprune, true, &result);
18251853

18261854
/* Expression eval may have used space in node's ps_ExprContext too */
1827-
ResetExprContext(pprune->context.planstate->ps_ExprContext);
1855+
if (pprune->initial_pruning_steps)
1856+
ResetExprContext(pprune->initial_context.planstate->ps_ExprContext);
18281857
}
18291858

18301859
/* Add in any subplans that partition pruning didn't account for */
@@ -1888,7 +1917,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
18881917
for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
18891918
{
18901919
PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
1891-
int nparts = pprune->context.nparts;
1920+
int nparts = pprune->nparts;
18921921
int k;
18931922

18941923
/* We just rebuild present_parts from scratch */
@@ -1993,7 +2022,8 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate)
19932022
find_matching_subplans_recurse(prunedata, pprune, false, &result);
19942023

19952024
/* Expression eval may have used space in node's ps_ExprContext too */
1996-
ResetExprContext(pprune->context.planstate->ps_ExprContext);
2025+
if (pprune->exec_pruning_steps)
2026+
ResetExprContext(pprune->exec_context.planstate->ps_ExprContext);
19972027
}
19982028

19992029
/* Add in any subplans that partition pruning didn't account for */
@@ -2029,15 +2059,15 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata,
20292059
check_stack_depth();
20302060

20312061
/* Only prune if pruning would be useful at this level. */
2032-
if (initial_prune ? pprune->do_initial_prune : pprune->do_exec_prune)
2062+
if (initial_prune && pprune->initial_pruning_steps)
20332063
{
2034-
PartitionPruneContext *context = &pprune->context;
2035-
2036-
/* Set whether we can evaluate PARAM_EXEC Params or not */
2037-
context->evalexecparams = !initial_prune;
2038-
2039-
partset = get_matching_partitions(context,
2040-
pprune->pruning_steps);
2064+
partset = get_matching_partitions(&pprune->initial_context,
2065+
pprune->initial_pruning_steps);
2066+
}
2067+
else if (!initial_prune && pprune->exec_pruning_steps)
2068+
{
2069+
partset = get_matching_partitions(&pprune->exec_context,
2070+
pprune->exec_pruning_steps);
20412071
}
20422072
else
20432073
{

src/backend/nodes/copyfuncs.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -1198,16 +1198,13 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from)
11981198
PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo);
11991199

12001200
COPY_SCALAR_FIELD(rtindex);
1201-
COPY_NODE_FIELD(pruning_steps);
12021201
COPY_BITMAPSET_FIELD(present_parts);
12031202
COPY_SCALAR_FIELD(nparts);
1204-
COPY_SCALAR_FIELD(nexprs);
12051203
COPY_POINTER_FIELD(subplan_map, from->nparts * sizeof(int));
12061204
COPY_POINTER_FIELD(subpart_map, from->nparts * sizeof(int));
12071205
COPY_POINTER_FIELD(relid_map, from->nparts * sizeof(Oid));
1208-
COPY_POINTER_FIELD(hasexecparam, from->nexprs * sizeof(bool));
1209-
COPY_SCALAR_FIELD(do_initial_prune);
1210-
COPY_SCALAR_FIELD(do_exec_prune);
1206+
COPY_NODE_FIELD(initial_pruning_steps);
1207+
COPY_NODE_FIELD(exec_pruning_steps);
12111208
COPY_BITMAPSET_FIELD(execparamids);
12121209

12131210
return newnode;

src/backend/nodes/outfuncs.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -948,16 +948,13 @@ _outPartitionedRelPruneInfo(StringInfo str, const PartitionedRelPruneInfo *node)
948948
WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO");
949949

950950
WRITE_UINT_FIELD(rtindex);
951-
WRITE_NODE_FIELD(pruning_steps);
952951
WRITE_BITMAPSET_FIELD(present_parts);
953952
WRITE_INT_FIELD(nparts);
954-
WRITE_INT_FIELD(nexprs);
955953
WRITE_INT_ARRAY(subplan_map, node->nparts);
956954
WRITE_INT_ARRAY(subpart_map, node->nparts);
957955
WRITE_OID_ARRAY(relid_map, node->nparts);
958-
WRITE_BOOL_ARRAY(hasexecparam, node->nexprs);
959-
WRITE_BOOL_FIELD(do_initial_prune);
960-
WRITE_BOOL_FIELD(do_exec_prune);
956+
WRITE_NODE_FIELD(initial_pruning_steps);
957+
WRITE_NODE_FIELD(exec_pruning_steps);
961958
WRITE_BITMAPSET_FIELD(execparamids);
962959
}
963960

src/backend/nodes/readfuncs.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -2388,16 +2388,13 @@ _readPartitionedRelPruneInfo(void)
23882388
READ_LOCALS(PartitionedRelPruneInfo);
23892389

23902390
READ_UINT_FIELD(rtindex);
2391-
READ_NODE_FIELD(pruning_steps);
23922391
READ_BITMAPSET_FIELD(present_parts);
23932392
READ_INT_FIELD(nparts);
2394-
READ_INT_FIELD(nexprs);
23952393
READ_INT_ARRAY(subplan_map, local_node->nparts);
23962394
READ_INT_ARRAY(subpart_map, local_node->nparts);
23972395
READ_OID_ARRAY(relid_map, local_node->nparts);
2398-
READ_BOOL_ARRAY(hasexecparam, local_node->nexprs);
2399-
READ_BOOL_FIELD(do_initial_prune);
2400-
READ_BOOL_FIELD(do_exec_prune);
2396+
READ_NODE_FIELD(initial_pruning_steps);
2397+
READ_NODE_FIELD(exec_pruning_steps);
24012398
READ_BITMAPSET_FIELD(execparamids);
24022399

24032400
READ_DONE();

0 commit comments

Comments
 (0)