Commit 6630ccad authored by Tom Lane's avatar Tom Lane

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
parent 05685897
...@@ -183,6 +183,11 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel, ...@@ -183,6 +183,11 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
bool *isnull, bool *isnull,
int maxfieldlen); int maxfieldlen);
static List *adjust_partition_tlist(List *tlist, TupleConversionMap *map); static List *adjust_partition_tlist(List *tlist, TupleConversionMap *map);
static void ExecInitPruningContext(PartitionPruneContext *context,
List *pruning_steps,
PartitionDesc partdesc,
PartitionKey partkey,
PlanState *planstate);
static void find_matching_subplans_recurse(PartitionPruningData *prunedata, static void find_matching_subplans_recurse(PartitionPruningData *prunedata,
PartitionedRelPruningData *pprune, PartitionedRelPruningData *pprune,
bool initial_prune, bool initial_prune,
...@@ -1614,16 +1619,9 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1614,16 +1619,9 @@ ExecCreatePartitionPruneState(PlanState *planstate,
{ {
PartitionedRelPruneInfo *pinfo = lfirst_node(PartitionedRelPruneInfo, lc2); PartitionedRelPruneInfo *pinfo = lfirst_node(PartitionedRelPruneInfo, lc2);
PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j]; PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
PartitionPruneContext *context = &pprune->context;
Relation partrel; Relation partrel;
PartitionDesc partdesc; PartitionDesc partdesc;
PartitionKey partkey; PartitionKey partkey;
int partnatts;
int n_steps;
ListCell *lc3;
/* present_parts is also subject to later modification */
pprune->present_parts = bms_copy(pinfo->present_parts);
/* /*
* We can rely on the copies of the partitioned table's partition * We can rely on the copies of the partitioned table's partition
...@@ -1643,6 +1641,7 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1643,6 +1641,7 @@ ExecCreatePartitionPruneState(PlanState *planstate,
* However, new partitions may have been added. * However, new partitions may have been added.
*/ */
Assert(partdesc->nparts >= pinfo->nparts); Assert(partdesc->nparts >= pinfo->nparts);
pprune->nparts = partdesc->nparts;
pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts); pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts);
if (partdesc->nparts == pinfo->nparts) if (partdesc->nparts == pinfo->nparts)
{ {
...@@ -1700,11 +1699,65 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1700,11 +1699,65 @@ ExecCreatePartitionPruneState(PlanState *planstate,
Assert(pd_idx == pinfo->nparts); Assert(pd_idx == pinfo->nparts);
} }
n_steps = list_length(pinfo->pruning_steps); /* present_parts is also subject to later modification */
pprune->present_parts = bms_copy(pinfo->present_parts);
/*
* Initialize pruning contexts as needed.
*/
pprune->initial_pruning_steps = pinfo->initial_pruning_steps;
if (pinfo->initial_pruning_steps)
{
ExecInitPruningContext(&pprune->initial_context,
pinfo->initial_pruning_steps,
partdesc, partkey, planstate);
/* Record whether initial pruning is needed at any level */
prunestate->do_initial_prune = true;
}
pprune->exec_pruning_steps = pinfo->exec_pruning_steps;
if (pinfo->exec_pruning_steps)
{
ExecInitPruningContext(&pprune->exec_context,
pinfo->exec_pruning_steps,
partdesc, partkey, planstate);
/* Record whether exec pruning is needed at any level */
prunestate->do_exec_prune = true;
}
/*
* Accumulate the IDs of all PARAM_EXEC Params affecting the
* partitioning decisions at this plan node.
*/
prunestate->execparamids = bms_add_members(prunestate->execparamids,
pinfo->execparamids);
j++;
}
i++;
}
return prunestate;
}
/*
* Initialize a PartitionPruneContext for the given list of pruning steps.
*/
static void
ExecInitPruningContext(PartitionPruneContext *context,
List *pruning_steps,
PartitionDesc partdesc,
PartitionKey partkey,
PlanState *planstate)
{
int n_steps;
int partnatts;
ListCell *lc;
n_steps = list_length(pruning_steps);
context->strategy = partkey->strategy; context->strategy = partkey->strategy;
context->partnatts = partnatts = partkey->partnatts; context->partnatts = partnatts = partkey->partnatts;
context->nparts = pinfo->nparts; context->nparts = partdesc->nparts;
context->boundinfo = partdesc->boundinfo; context->boundinfo = partdesc->boundinfo;
context->partcollation = partkey->partcollation; context->partcollation = partkey->partcollation;
context->partsupfunc = partkey->partsupfunc; context->partsupfunc = partkey->partsupfunc;
...@@ -1719,10 +1772,10 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1719,10 +1772,10 @@ ExecCreatePartitionPruneState(PlanState *planstate,
/* Initialize expression state for each expression we need */ /* Initialize expression state for each expression we need */
context->exprstates = (ExprState **) context->exprstates = (ExprState **)
palloc0(sizeof(ExprState *) * n_steps * partnatts); palloc0(sizeof(ExprState *) * n_steps * partnatts);
foreach(lc3, pinfo->pruning_steps) foreach(lc, pruning_steps)
{ {
PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc3); PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc);
ListCell *lc4; ListCell *lc2;
int keyno; int keyno;
/* not needed for other step kinds */ /* not needed for other step kinds */
...@@ -1732,9 +1785,9 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1732,9 +1785,9 @@ ExecCreatePartitionPruneState(PlanState *planstate,
Assert(list_length(step->exprs) <= partnatts); Assert(list_length(step->exprs) <= partnatts);
keyno = 0; keyno = 0;
foreach(lc4, step->exprs) foreach(lc2, step->exprs)
{ {
Expr *expr = (Expr *) lfirst(lc4); Expr *expr = (Expr *) lfirst(lc2);
/* not needed for Consts */ /* not needed for Consts */
if (!IsA(expr, Const)) if (!IsA(expr, Const))
...@@ -1749,31 +1802,6 @@ ExecCreatePartitionPruneState(PlanState *planstate, ...@@ -1749,31 +1802,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
keyno++; keyno++;
} }
} }
/* Array is not modified at runtime, so just point to plan's copy */
context->exprhasexecparam = pinfo->hasexecparam;
pprune->pruning_steps = pinfo->pruning_steps;
pprune->do_initial_prune = pinfo->do_initial_prune;
pprune->do_exec_prune = pinfo->do_exec_prune;
/* Record if pruning would be useful at any level */
prunestate->do_initial_prune |= pinfo->do_initial_prune;
prunestate->do_exec_prune |= pinfo->do_exec_prune;
/*
* Accumulate the IDs of all PARAM_EXEC Params affecting the
* partitioning decisions at this plan node.
*/
prunestate->execparamids = bms_add_members(prunestate->execparamids,
pinfo->execparamids);
j++;
}
i++;
}
return prunestate;
} }
/* /*
...@@ -1824,7 +1852,8 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans) ...@@ -1824,7 +1852,8 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
find_matching_subplans_recurse(prunedata, pprune, true, &result); find_matching_subplans_recurse(prunedata, pprune, true, &result);
/* Expression eval may have used space in node's ps_ExprContext too */ /* Expression eval may have used space in node's ps_ExprContext too */
ResetExprContext(pprune->context.planstate->ps_ExprContext); if (pprune->initial_pruning_steps)
ResetExprContext(pprune->initial_context.planstate->ps_ExprContext);
} }
/* Add in any subplans that partition pruning didn't account for */ /* Add in any subplans that partition pruning didn't account for */
...@@ -1888,7 +1917,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans) ...@@ -1888,7 +1917,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--) for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
{ {
PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j]; PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
int nparts = pprune->context.nparts; int nparts = pprune->nparts;
int k; int k;
/* We just rebuild present_parts from scratch */ /* We just rebuild present_parts from scratch */
...@@ -1993,7 +2022,8 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate) ...@@ -1993,7 +2022,8 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate)
find_matching_subplans_recurse(prunedata, pprune, false, &result); find_matching_subplans_recurse(prunedata, pprune, false, &result);
/* Expression eval may have used space in node's ps_ExprContext too */ /* Expression eval may have used space in node's ps_ExprContext too */
ResetExprContext(pprune->context.planstate->ps_ExprContext); if (pprune->exec_pruning_steps)
ResetExprContext(pprune->exec_context.planstate->ps_ExprContext);
} }
/* Add in any subplans that partition pruning didn't account for */ /* Add in any subplans that partition pruning didn't account for */
...@@ -2029,15 +2059,15 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata, ...@@ -2029,15 +2059,15 @@ find_matching_subplans_recurse(PartitionPruningData *prunedata,
check_stack_depth(); check_stack_depth();
/* Only prune if pruning would be useful at this level. */ /* Only prune if pruning would be useful at this level. */
if (initial_prune ? pprune->do_initial_prune : pprune->do_exec_prune) if (initial_prune && pprune->initial_pruning_steps)
{ {
PartitionPruneContext *context = &pprune->context; partset = get_matching_partitions(&pprune->initial_context,
pprune->initial_pruning_steps);
/* Set whether we can evaluate PARAM_EXEC Params or not */ }
context->evalexecparams = !initial_prune; else if (!initial_prune && pprune->exec_pruning_steps)
{
partset = get_matching_partitions(context, partset = get_matching_partitions(&pprune->exec_context,
pprune->pruning_steps); pprune->exec_pruning_steps);
} }
else else
{ {
......
...@@ -1198,16 +1198,13 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from) ...@@ -1198,16 +1198,13 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from)
PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo); PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo);
COPY_SCALAR_FIELD(rtindex); COPY_SCALAR_FIELD(rtindex);
COPY_NODE_FIELD(pruning_steps);
COPY_BITMAPSET_FIELD(present_parts); COPY_BITMAPSET_FIELD(present_parts);
COPY_SCALAR_FIELD(nparts); COPY_SCALAR_FIELD(nparts);
COPY_SCALAR_FIELD(nexprs);
COPY_POINTER_FIELD(subplan_map, from->nparts * sizeof(int)); COPY_POINTER_FIELD(subplan_map, from->nparts * sizeof(int));
COPY_POINTER_FIELD(subpart_map, from->nparts * sizeof(int)); COPY_POINTER_FIELD(subpart_map, from->nparts * sizeof(int));
COPY_POINTER_FIELD(relid_map, from->nparts * sizeof(Oid)); COPY_POINTER_FIELD(relid_map, from->nparts * sizeof(Oid));
COPY_POINTER_FIELD(hasexecparam, from->nexprs * sizeof(bool)); COPY_NODE_FIELD(initial_pruning_steps);
COPY_SCALAR_FIELD(do_initial_prune); COPY_NODE_FIELD(exec_pruning_steps);
COPY_SCALAR_FIELD(do_exec_prune);
COPY_BITMAPSET_FIELD(execparamids); COPY_BITMAPSET_FIELD(execparamids);
return newnode; return newnode;
......
...@@ -948,16 +948,13 @@ _outPartitionedRelPruneInfo(StringInfo str, const PartitionedRelPruneInfo *node) ...@@ -948,16 +948,13 @@ _outPartitionedRelPruneInfo(StringInfo str, const PartitionedRelPruneInfo *node)
WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO"); WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO");
WRITE_UINT_FIELD(rtindex); WRITE_UINT_FIELD(rtindex);
WRITE_NODE_FIELD(pruning_steps);
WRITE_BITMAPSET_FIELD(present_parts); WRITE_BITMAPSET_FIELD(present_parts);
WRITE_INT_FIELD(nparts); WRITE_INT_FIELD(nparts);
WRITE_INT_FIELD(nexprs);
WRITE_INT_ARRAY(subplan_map, node->nparts); WRITE_INT_ARRAY(subplan_map, node->nparts);
WRITE_INT_ARRAY(subpart_map, node->nparts); WRITE_INT_ARRAY(subpart_map, node->nparts);
WRITE_OID_ARRAY(relid_map, node->nparts); WRITE_OID_ARRAY(relid_map, node->nparts);
WRITE_BOOL_ARRAY(hasexecparam, node->nexprs); WRITE_NODE_FIELD(initial_pruning_steps);
WRITE_BOOL_FIELD(do_initial_prune); WRITE_NODE_FIELD(exec_pruning_steps);
WRITE_BOOL_FIELD(do_exec_prune);
WRITE_BITMAPSET_FIELD(execparamids); WRITE_BITMAPSET_FIELD(execparamids);
} }
......
...@@ -2388,16 +2388,13 @@ _readPartitionedRelPruneInfo(void) ...@@ -2388,16 +2388,13 @@ _readPartitionedRelPruneInfo(void)
READ_LOCALS(PartitionedRelPruneInfo); READ_LOCALS(PartitionedRelPruneInfo);
READ_UINT_FIELD(rtindex); READ_UINT_FIELD(rtindex);
READ_NODE_FIELD(pruning_steps);
READ_BITMAPSET_FIELD(present_parts); READ_BITMAPSET_FIELD(present_parts);
READ_INT_FIELD(nparts); READ_INT_FIELD(nparts);
READ_INT_FIELD(nexprs);
READ_INT_ARRAY(subplan_map, local_node->nparts); READ_INT_ARRAY(subplan_map, local_node->nparts);
READ_INT_ARRAY(subpart_map, local_node->nparts); READ_INT_ARRAY(subpart_map, local_node->nparts);
READ_OID_ARRAY(relid_map, local_node->nparts); READ_OID_ARRAY(relid_map, local_node->nparts);
READ_BOOL_ARRAY(hasexecparam, local_node->nexprs); READ_NODE_FIELD(initial_pruning_steps);
READ_BOOL_FIELD(do_initial_prune); READ_NODE_FIELD(exec_pruning_steps);
READ_BOOL_FIELD(do_exec_prune);
READ_BITMAPSET_FIELD(execparamids); READ_BITMAPSET_FIELD(execparamids);
READ_DONE(); READ_DONE();
......
This diff is collapsed.
...@@ -58,28 +58,30 @@ typedef struct PartitionRoutingInfo ...@@ -58,28 +58,30 @@ typedef struct PartitionRoutingInfo
* PartitionedRelPruneInfo (see plannodes.h); though note that here, * PartitionedRelPruneInfo (see plannodes.h); though note that here,
* subpart_map contains indexes into PartitionPruningData.partrelprunedata[]. * subpart_map contains indexes into PartitionPruningData.partrelprunedata[].
* *
* nparts Length of subplan_map[] and subpart_map[].
* subplan_map Subplan index by partition index, or -1. * subplan_map Subplan index by partition index, or -1.
* subpart_map Subpart index by partition index, or -1. * subpart_map Subpart index by partition index, or -1.
* present_parts A Bitmapset of the partition indexes that we * present_parts A Bitmapset of the partition indexes that we
* have subplans or subparts for. * have subplans or subparts for.
* context Contains the context details required to call * initial_pruning_steps List of PartitionPruneSteps used to
* the partition pruning code. * perform executor startup pruning.
* pruning_steps List of PartitionPruneSteps used to * exec_pruning_steps List of PartitionPruneSteps used to
* perform the actual pruning. * perform per-scan pruning.
* do_initial_prune true if pruning should be performed during * initial_context If initial_pruning_steps isn't NIL, contains
* executor startup (for this partitioning level). * the details needed to execute those steps.
* do_exec_prune true if pruning should be performed during * exec_context If exec_pruning_steps isn't NIL, contains
* executor run (for this partitioning level). * the details needed to execute those steps.
*/ */
typedef struct PartitionedRelPruningData typedef struct PartitionedRelPruningData
{ {
int nparts;
int *subplan_map; int *subplan_map;
int *subpart_map; int *subpart_map;
Bitmapset *present_parts; Bitmapset *present_parts;
PartitionPruneContext context; List *initial_pruning_steps;
List *pruning_steps; List *exec_pruning_steps;
bool do_initial_prune; PartitionPruneContext initial_context;
bool do_exec_prune; PartitionPruneContext exec_context;
} PartitionedRelPruningData; } PartitionedRelPruningData;
/* /*
......
...@@ -1109,21 +1109,23 @@ typedef struct PartitionedRelPruneInfo ...@@ -1109,21 +1109,23 @@ typedef struct PartitionedRelPruneInfo
{ {
NodeTag type; NodeTag type;
Index rtindex; /* RT index of partition rel for this level */ Index rtindex; /* RT index of partition rel for this level */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */ * subparts are present for */
int nparts; /* Length of subplan_map[] and subpart_map[] */ int nparts; /* Length of the following arrays: */
int nexprs; /* Length of hasexecparam[] */
int *subplan_map; /* subplan index by partition index, or -1 */ int *subplan_map; /* subplan index by partition index, or -1 */
int *subpart_map; /* subpart index by partition index, or -1 */ int *subpart_map; /* subpart index by partition index, or -1 */
Oid *relid_map; /* relation OID by partition index, or 0 */ Oid *relid_map; /* relation OID by partition index, or 0 */
bool *hasexecparam; /* true if corresponding pruning_step contains
* any PARAM_EXEC Params. */ /*
bool do_initial_prune; /* true if pruning should be performed * initial_pruning_steps shows how to prune during executor startup (i.e.,
* during executor startup. */ * without use of any PARAM_EXEC Params); it is NIL if no startup pruning
bool do_exec_prune; /* true if pruning should be performed during * is required. exec_pruning_steps shows how to prune with PARAM_EXEC
* executor run. */ * Params; it is NIL if no per-scan pruning is required.
Bitmapset *execparamids; /* All PARAM_EXEC Param IDs in pruning_steps */ */
List *initial_pruning_steps; /* List of PartitionPruneStep */
List *exec_pruning_steps; /* List of PartitionPruneStep */
Bitmapset *execparamids; /* All PARAM_EXEC Param IDs in
* exec_pruning_steps */
} PartitionedRelPruneInfo; } PartitionedRelPruneInfo;
/* /*
......
...@@ -44,10 +44,6 @@ struct RelOptInfo; ...@@ -44,10 +44,6 @@ struct RelOptInfo;
* exprstates Array of ExprStates, indexed as per PruneCtxStateIdx; one * exprstates Array of ExprStates, indexed as per PruneCtxStateIdx; one
* for each partition key in each pruning step. Allocated if * for each partition key in each pruning step. Allocated if
* planstate is non-NULL, otherwise NULL. * planstate is non-NULL, otherwise NULL.
* exprhasexecparam Array of bools, each true if corresponding 'exprstate'
* expression contains any PARAM_EXEC Params. (Can be NULL
* if planstate is NULL.)
* evalexecparams True if it's safe to evaluate PARAM_EXEC Params.
*/ */
typedef struct PartitionPruneContext typedef struct PartitionPruneContext
{ {
...@@ -61,8 +57,6 @@ typedef struct PartitionPruneContext ...@@ -61,8 +57,6 @@ typedef struct PartitionPruneContext
MemoryContext ppccontext; MemoryContext ppccontext;
PlanState *planstate; PlanState *planstate;
ExprState **exprstates; ExprState **exprstates;
bool *exprhasexecparam;
bool evalexecparams;
} PartitionPruneContext; } PartitionPruneContext;
/* /*
......
...@@ -3149,6 +3149,45 @@ select * from mc3p where a < 3 and abs(b) = 1; ...@@ -3149,6 +3149,45 @@ select * from mc3p where a < 3 and abs(b) = 1;
Filter: ((a < 3) AND (abs(b) = 1)) Filter: ((a < 3) AND (abs(b) = 1))
(7 rows) (7 rows)
--
-- Check that pruning with composite range partitioning works correctly when
-- a combination of runtime parameters is specified, not all of whose values
-- are available at the same time
--
set plan_cache_mode = force_generic_plan;
prepare ps1 as
select * from mc3p where a = $1 and abs(b) < (select 3);
explain (analyze, costs off, summary off, timing off)
execute ps1(1);
QUERY PLAN
-------------------------------------------------
Append (actual rows=1 loops=1)
InitPlan 1 (returns $0)
-> Result (actual rows=1 loops=1)
Subplans Removed: 2
-> Seq Scan on mc3p1 (actual rows=1 loops=1)
Filter: ((a = $1) AND (abs(b) < $0))
(6 rows)
deallocate ps1;
prepare ps2 as
select * from mc3p where a <= $1 and abs(b) < (select 3);
explain (analyze, costs off, summary off, timing off)
execute ps2(1);
QUERY PLAN
-------------------------------------------------
Append (actual rows=2 loops=1)
InitPlan 1 (returns $0)
-> Result (actual rows=1 loops=1)
Subplans Removed: 1
-> Seq Scan on mc3p0 (actual rows=1 loops=1)
Filter: ((a <= $1) AND (abs(b) < $0))
-> Seq Scan on mc3p1 (actual rows=1 loops=1)
Filter: ((a <= $1) AND (abs(b) < $0))
(8 rows)
deallocate ps2;
reset plan_cache_mode;
drop table mc3p; drop table mc3p;
-- Ensure runtime pruning works with initplans params with boolean types -- Ensure runtime pruning works with initplans params with boolean types
create table boolvalues (value bool not null); create table boolvalues (value bool not null);
......
...@@ -809,6 +809,24 @@ insert into mc3p values (0, 1, 1), (1, 1, 1), (2, 1, 1); ...@@ -809,6 +809,24 @@ insert into mc3p values (0, 1, 1), (1, 1, 1), (2, 1, 1);
explain (analyze, costs off, summary off, timing off) explain (analyze, costs off, summary off, timing off)
select * from mc3p where a < 3 and abs(b) = 1; select * from mc3p where a < 3 and abs(b) = 1;
--
-- Check that pruning with composite range partitioning works correctly when
-- a combination of runtime parameters is specified, not all of whose values
-- are available at the same time
--
set plan_cache_mode = force_generic_plan;
prepare ps1 as
select * from mc3p where a = $1 and abs(b) < (select 3);
explain (analyze, costs off, summary off, timing off)
execute ps1(1);
deallocate ps1;
prepare ps2 as
select * from mc3p where a <= $1 and abs(b) < (select 3);
explain (analyze, costs off, summary off, timing off)
execute ps2(1);
deallocate ps2;
reset plan_cache_mode;
drop table mc3p; drop table mc3p;
-- Ensure runtime pruning works with initplans params with boolean types -- Ensure runtime pruning works with initplans params with boolean types
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment