diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 2efb2c864de..f128b99c36a 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -46,6 +46,7 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/appendinfo.h" +#include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/optimizer.h" #include "optimizer/pathnode.h" @@ -2073,7 +2074,11 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, /* * See if there are any exec Params. If so, we can only use this - * expression during per-scan pruning. + * expression during per-scan pruning. The same is true if it + * contains a SubPlan, as evaluating that requires the parent + * node's PlanState, which startup-time pruning hasn't got. (A + * SubPlan's testexpr normally contains exec Params, so we'd have + * caught it above, but the testexpr can be folded to a Const.) */ paramids = pull_exec_paramids(expr); if (!bms_is_empty(paramids)) @@ -2082,6 +2087,11 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, if (context->target != PARTTARGET_EXEC) return PARTCLAUSE_UNSUPPORTED; } + else if (contain_subplans((Node *) expr)) + { + if (context->target != PARTTARGET_EXEC) + return PARTCLAUSE_UNSUPPORTED; + } else { /* It's potentially usable, but mutable */ diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 191901210a8..3506ecec477 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -2106,6 +2106,22 @@ where asptab.id > ss.b::int; -> Seq Scan on int4_tbl tinner (14 rows) +-- check that a SubPlan in a pruning expression is not used for startup-time +-- pruning, which has no parent PlanState to evaluate the SubPlan with +explain (costs off) +select * from asptab where id = (null::int in (select f1 from int4_tbl))::int; + QUERY PLAN +-------------------------------------------------------------- + Append + -> Index Only Scan using asptab0_pkey on asptab0 asptab_1 + Index Cond: (id = ((ANY NULL::boolean))::integer) + SubPlan any_1 + -> Materialize + -> Seq Scan on int4_tbl + -> Index Only Scan using asptab1_pkey on asptab1 asptab_2 + Index Cond: (id = ((ANY NULL::boolean))::integer) +(8 rows) + drop table asptab; -- -- Test Partition pruning for HASH partitioning diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 01f44538fb6..d6e096dc565 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -488,6 +488,12 @@ select * from asptab where asptab.id > ss.b::int; +-- check that a SubPlan in a pruning expression is not used for startup-time +-- pruning, which has no parent PlanState to evaluate the SubPlan with + +explain (costs off) +select * from asptab where id = (null::int in (select f1 from int4_tbl))::int; + drop table asptab; --