diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index eb8a87fd63..eec84115a7 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -2108,7 +2108,8 @@ InitPartitionPruneContext(PartitionPruneContext *context, foreach(lc, pruning_steps) { PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc); - ListCell *lc2; + ListCell *lc2 = list_head(step->exprs); + int keyno; /* not needed for other step kinds */ @@ -2117,34 +2118,39 @@ InitPartitionPruneContext(PartitionPruneContext *context, Assert(list_length(step->exprs) <= partnatts); - keyno = 0; - foreach(lc2, step->exprs) + for (keyno = 0; keyno < partnatts; keyno++) { - Expr *expr = (Expr *) lfirst(lc2); + if (bms_is_member(keyno, step->nullkeys)) + continue; /* not needed for Consts */ - if (!IsA(expr, Const)) + if (lc2 != NULL) { - int stateidx = PruneCxtStateIdx(partnatts, - step->step.step_id, - keyno); + Expr *expr = lfirst(lc2); - /* - * When planstate is NULL, pruning_steps is known not to - * contain any expressions that depend on the parent plan. - * Information of any available EXTERN parameters must be - * passed explicitly in that case, which the caller must have - * made available via econtext. - */ - if (planstate == NULL) - context->exprstates[stateidx] = - ExecInitExprWithParams(expr, - econtext->ecxt_param_list_info); - else - context->exprstates[stateidx] = - ExecInitExpr(expr, context->planstate); + if (!IsA(expr, Const)) + { + int stateidx = PruneCxtStateIdx(partnatts, + step->step.step_id, + keyno); + + /* + * When planstate is NULL, pruning_steps is known not to + * contain any expressions that depend on the parent plan. + * Information of any available EXTERN parameters must be + * passed explicitly in that case, which the caller must have + * made available via econtext. + */ + if (planstate == NULL) + context->exprstates[stateidx] = + ExecInitExprWithParams(expr, + econtext->ecxt_param_list_info); + else + context->exprstates[stateidx] = + ExecInitExpr(expr, context->planstate); + } + lc2 = lnext(step->exprs, lc2); } - keyno++; } } } diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index bb1223e2b1..36791293ee 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1921,6 +1921,19 @@ explain (costs off) select * from hp where (a = 1 and b = 'abcde') or (a = 2 and Filter: (((a = 1) AND (b = 'abcde'::text)) OR ((a = 2) AND (b = 'xxx'::text)) OR ((a IS NULL) AND (b IS NULL))) (7 rows) +-- test run-time pruning +set plan_cache_mode = 'force_generic_plan'; +prepare stmt (text) AS select * from hp where a is null and b = $1; +explain (costs off) execute stmt('xxx'); + QUERY PLAN +-------------------------------------------- + Append + Subplans Removed: 3 + -> Seq Scan on hp2 hp_1 + Filter: ((a IS NULL) AND (b = $1)) +(4 rows) + +deallocate stmt; -- test pruning when not all the partitions exist drop table hp1; drop table hp3; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 83fed54b8c..d23133fe43 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -374,6 +374,12 @@ explain (costs off) select * from hp where a = 2 and b = 'xxx'; explain (costs off) select * from hp where a = 1 and b = 'abcde'; explain (costs off) select * from hp where (a = 1 and b = 'abcde') or (a = 2 and b = 'xxx') or (a is null and b is null); +-- test run-time pruning +set plan_cache_mode = 'force_generic_plan'; +prepare stmt (text) AS select * from hp where a is null and b = $1; +explain (costs off) execute stmt('xxx'); +deallocate stmt; + -- test pruning when not all the partitions exist drop table hp1; drop table hp3;