summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeAppend.c42
-rw-r--r--src/backend/executor/nodeMergeAppend.c30
-rw-r--r--src/include/nodes/execnodes.h3
-rw-r--r--src/test/regress/expected/partition_prune.out83
-rw-r--r--src/test/regress/sql/partition_prune.sql15
5 files changed, 69 insertions, 104 deletions
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 5ff986ac7d3..8b12a24cd5e 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -78,7 +78,6 @@ struct ParallelAppendState
};
#define INVALID_SUBPLAN_INDEX -1
-#define NO_MATCHING_SUBPLANS -2
static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool choose_next_subplan_locally(AppendState *node);
@@ -141,23 +140,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
validsubplans = ExecFindInitialMatchingSubPlans(prunestate,
list_length(node->appendplans));
- /*
- * The case where no subplans survive pruning must be handled
- * specially. The problem here is that code in explain.c requires
- * an Append to have at least one subplan in order for it to
- * properly determine the Vars in that subplan's targetlist. We
- * sidestep this issue by just initializing the first subplan and
- * setting as_whichplan to NO_MATCHING_SUBPLANS to indicate that
- * we don't really need to scan any subnodes.
- */
- if (bms_is_empty(validsubplans))
- {
- appendstate->as_whichplan = NO_MATCHING_SUBPLANS;
-
- /* Mark the first as valid so that it's initialized below */
- validsubplans = bms_make_singleton(0);
- }
-
nplans = bms_num_members(validsubplans);
}
else
@@ -169,14 +151,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
}
/*
- * If no runtime pruning is required, we can fill as_valid_subplans
- * immediately, preventing later calls to ExecFindMatchingSubPlans.
+ * When no run-time pruning is required and there's at least one
+ * subplan, we can fill as_valid_subplans immediately, preventing
+ * later calls to ExecFindMatchingSubPlans.
*/
- if (!prunestate->do_exec_prune)
- {
- Assert(nplans > 0);
+ if (!prunestate->do_exec_prune && nplans > 0)
appendstate->as_valid_subplans = bms_add_range(NULL, 0, nplans - 1);
- }
}
else
{
@@ -255,6 +235,10 @@ ExecAppend(PlanState *pstate)
if (node->as_whichplan < 0)
{
+ /* Nothing to do if there are no subplans */
+ if (node->as_nplans == 0)
+ return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
/*
* If no subplan has been chosen, we must choose one before
* proceeding.
@@ -262,10 +246,6 @@ ExecAppend(PlanState *pstate)
if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
!node->choose_next_subplan(node))
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
-
- /* Nothing to do if there are no matching subplans */
- else if (node->as_whichplan == NO_MATCHING_SUBPLANS)
- return ExecClearTuple(node->ps.ps_ResultTupleSlot);
}
for (;;)
@@ -460,7 +440,7 @@ choose_next_subplan_locally(AppendState *node)
int nextplan;
/* We should never be called when there are no subplans */
- Assert(whichplan != NO_MATCHING_SUBPLANS);
+ Assert(node->as_nplans > 0);
/*
* If first call then have the bms member function choose the first valid
@@ -511,7 +491,7 @@ choose_next_subplan_for_leader(AppendState *node)
Assert(ScanDirectionIsForward(node->ps.state->es_direction));
/* We should never be called when there are no subplans */
- Assert(node->as_whichplan != NO_MATCHING_SUBPLANS);
+ Assert(node->as_nplans > 0);
LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
@@ -592,7 +572,7 @@ choose_next_subplan_for_worker(AppendState *node)
Assert(ScanDirectionIsForward(node->ps.state->es_direction));
/* We should never be called when there are no subplans */
- Assert(node->as_whichplan != NO_MATCHING_SUBPLANS);
+ Assert(node->as_nplans > 0);
LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 18d13377dc3..e6896eff742 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -80,7 +80,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
mergestate->ps.plan = (Plan *) node;
mergestate->ps.state = estate;
mergestate->ps.ExecProcNode = ExecMergeAppend;
- mergestate->ms_noopscan = false;
/* If run-time partition pruning is enabled, then set that up now */
if (node->part_prune_info != NULL)
@@ -101,23 +100,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
validsubplans = ExecFindInitialMatchingSubPlans(prunestate,
list_length(node->mergeplans));
- /*
- * The case where no subplans survive pruning must be handled
- * specially. The problem here is that code in explain.c requires
- * a MergeAppend to have at least one subplan in order for it to
- * properly determine the Vars in that subplan's targetlist. We
- * sidestep this issue by just initializing the first subplan and
- * setting ms_noopscan to true to indicate that we don't really
- * need to scan any subnodes.
- */
- if (bms_is_empty(validsubplans))
- {
- mergestate->ms_noopscan = true;
-
- /* Mark the first as valid so that it's initialized below */
- validsubplans = bms_make_singleton(0);
- }
-
nplans = bms_num_members(validsubplans);
}
else
@@ -129,14 +111,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
}
/*
- * If no runtime pruning is required, we can fill ms_valid_subplans
- * immediately, preventing later calls to ExecFindMatchingSubPlans.
+ * When no run-time pruning is required and there's at least one
+ * subplan, we can fill as_valid_subplans immediately, preventing
+ * later calls to ExecFindMatchingSubPlans.
*/
- if (!prunestate->do_exec_prune)
- {
- Assert(nplans > 0);
+ if (!prunestate->do_exec_prune && nplans > 0)
mergestate->ms_valid_subplans = bms_add_range(NULL, 0, nplans - 1);
- }
}
else
{
@@ -240,7 +220,7 @@ ExecMergeAppend(PlanState *pstate)
if (!node->ms_initialized)
{
/* Nothing to do if all subplans were pruned */
- if (node->ms_noopscan)
+ if (node->ms_nplans == 0)
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ea93b769e1d..0c2a77aaf8d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1234,8 +1234,6 @@ struct AppendState
* slots current output tuple of each subplan
* heap heap of active tuples
* initialized true if we have fetched first tuple from each subplan
- * noopscan true if partition pruning proved that none of the
- * mergeplans can contain a record to satisfy this query.
* prune_state details required to allow partitions to be
* eliminated from the scan, or NULL if not possible.
* valid_subplans for runtime pruning, valid mergeplans indexes to
@@ -1252,7 +1250,6 @@ typedef struct MergeAppendState
TupleTableSlot **ms_slots; /* array of length ms_nplans */
struct binaryheap *ms_heap; /* binary heap of slot indices */
bool ms_initialized; /* are subplans started? */
- bool ms_noopscan;
struct PartitionPruneState *ms_prune_state;
Bitmapset *ms_valid_subplans;
} MergeAppendState;
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 57680f1d292..6dc50e0aa4e 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -2005,20 +2005,17 @@ select explain_parallel_append('execute ab_q5 (2, 3, 3)');
(19 rows)
-- Try some params whose values do not belong to any partition.
--- We'll still get a single subplan in this case, but it should not be scanned.
select explain_parallel_append('execute ab_q5 (33, 44, 55)');
- explain_parallel_append
--------------------------------------------------------------------------------
+ explain_parallel_append
+-----------------------------------------------------------
Finalize Aggregate (actual rows=N loops=N)
-> Gather (actual rows=N loops=N)
Workers Planned: 2
Workers Launched: N
-> Partial Aggregate (actual rows=N loops=N)
-> Parallel Append (actual rows=N loops=N)
- Subplans Removed: 8
- -> Parallel Seq Scan on ab_a1_b1 ab_1 (never executed)
- Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3])))
-(9 rows)
+ Subplans Removed: 9
+(7 rows)
-- Test Parallel Append with PARAM_EXEC Params
select explain_parallel_append('select count(*) from ab where (a = (select 1) or a = (select 3)) and b = 2');
@@ -2854,16 +2851,13 @@ explain (analyze, costs off, summary off, timing off) execute q1 (2,2);
Filter: (b = ANY (ARRAY[$1, $2]))
(4 rows)
--- Try with no matching partitions. One subplan should remain in this case,
--- but it shouldn't be executed.
+-- Try with no matching partitions.
explain (analyze, costs off, summary off, timing off) execute q1 (0,0);
- QUERY PLAN
-------------------------------------------------------
+ QUERY PLAN
+--------------------------------
Append (actual rows=0 loops=1)
- Subplans Removed: 1
- -> Seq Scan on listp_1_1 listp_1 (never executed)
- Filter: (b = ANY (ARRAY[$1, $2]))
-(4 rows)
+ Subplans Removed: 2
+(2 rows)
deallocate q1;
-- Test more complex cases where a not-equal condition further eliminates partitions.
@@ -2879,15 +2873,12 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0);
(4 rows)
-- Both partitions allowed by IN clause, then both excluded again by <> clauses.
--- One subplan will remain in this case, but it should not be executed.
explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1);
- QUERY PLAN
--------------------------------------------------------------------------
+ QUERY PLAN
+--------------------------------
Append (actual rows=0 loops=1)
- Subplans Removed: 1
- -> Seq Scan on listp_1_1 listp_1 (never executed)
- Filter: ((b = ANY (ARRAY[$1, $2])) AND ($3 <> b) AND ($4 <> b))
-(4 rows)
+ Subplans Removed: 2
+(2 rows)
-- Ensure Params that evaluate to NULL properly prune away all partitions
explain (analyze, costs off, summary off, timing off)
@@ -2971,13 +2962,11 @@ select * from stable_qual_pruning
explain (analyze, costs off, summary off, timing off)
select * from stable_qual_pruning
where a = any(array['2010-02-01', '2020-01-01']::timestamptz[]);
- QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+--------------------------------
Append (actual rows=0 loops=1)
- Subplans Removed: 2
- -> Seq Scan on stable_qual_pruning1 stable_qual_pruning_1 (never executed)
- Filter: (a = ANY ('{"Mon Feb 01 00:00:00 2010 PST","Wed Jan 01 00:00:00 2020 PST"}'::timestamp with time zone[]))
-(4 rows)
+ Subplans Removed: 3
+(2 rows)
explain (analyze, costs off, summary off, timing off)
select * from stable_qual_pruning
@@ -3159,14 +3148,12 @@ execute mt_q1(25);
-- Ensure MergeAppend behaves correctly when no subplans match
explain (analyze, costs off, summary off, timing off) execute mt_q1(35);
- QUERY PLAN
-----------------------------------------------------------------------------------
+ QUERY PLAN
+--------------------------------------
Merge Append (actual rows=0 loops=1)
Sort Key: ma_test.b
- Subplans Removed: 2
- -> Index Scan using ma_test_p1_b_idx on ma_test_p1 ma_test_1 (never executed)
- Filter: ((a >= $1) AND ((a % 10) = 5))
-(5 rows)
+ Subplans Removed: 3
+(3 rows)
execute mt_q1(35);
a
@@ -3174,6 +3161,21 @@ execute mt_q1(35);
(0 rows)
deallocate mt_q1;
+set plan_cache_mode = force_generic_plan;
+prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1;
+-- Ensure output list looks sane when the MergeAppend has no subplans.
+explain (analyze, verbose, costs off, summary off, timing off) execute mt_q2 (35);
+ QUERY PLAN
+--------------------------------------------
+ Limit (actual rows=0 loops=1)
+ Output: ma_test.a, ma_test.b
+ -> Merge Append (actual rows=0 loops=1)
+ Sort Key: ma_test.b
+ Subplans Removed: 3
+(5 rows)
+
+deallocate mt_q2;
+reset plan_cache_mode;
-- ensure initplan params properly prune partitions
explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b;
QUERY PLAN
@@ -3591,19 +3593,18 @@ from (
) s(a, b, c)
where s.a = $1 and s.b = $2 and s.c = (select 1);
explain (costs off) execute q (1, 1);
- QUERY PLAN
----------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------
Append
InitPlan 1 (returns $0)
-> Result
- Subplans Removed: 1
-> Seq Scan on p1 p
- Filter: ((a = $1) AND (b = $2) AND (c = $0))
+ Filter: ((a = 1) AND (b = 1) AND (c = $0))
-> Seq Scan on q111 q1
- Filter: ((a = $1) AND (b = $2) AND (c = $0))
+ Filter: ((a = 1) AND (b = 1) AND (c = $0))
-> Result
- One-Time Filter: ((1 = $1) AND (1 = $2) AND (1 = $0))
-(10 rows)
+ One-Time Filter: (1 = $0)
+(9 rows)
execute q (1, 1);
a | b | c
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index 41f0b6f1102..e00984edd45 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -477,7 +477,6 @@ select explain_parallel_append('execute ab_q5 (1, 1, 1)');
select explain_parallel_append('execute ab_q5 (2, 3, 3)');
-- Try some params whose values do not belong to any partition.
--- We'll still get a single subplan in this case, but it should not be scanned.
select explain_parallel_append('execute ab_q5 (33, 44, 55)');
-- Test Parallel Append with PARAM_EXEC Params
@@ -702,8 +701,7 @@ explain (analyze, costs off, summary off, timing off) execute q1 (1,1);
explain (analyze, costs off, summary off, timing off) execute q1 (2,2);
--- Try with no matching partitions. One subplan should remain in this case,
--- but it shouldn't be executed.
+-- Try with no matching partitions.
explain (analyze, costs off, summary off, timing off) execute q1 (0,0);
deallocate q1;
@@ -715,7 +713,6 @@ prepare q1 (int,int,int,int) as select * from listp where b in($1,$2) and $3 <>
explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,0);
-- Both partitions allowed by IN clause, then both excluded again by <> clauses.
--- One subplan will remain in this case, but it should not be executed.
explain (analyze, costs off, summary off, timing off) execute q1 (1,2,2,1);
-- Ensure Params that evaluate to NULL properly prune away all partitions
@@ -841,6 +838,16 @@ execute mt_q1(35);
deallocate mt_q1;
+set plan_cache_mode = force_generic_plan;
+
+prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1;
+
+-- Ensure output list looks sane when the MergeAppend has no subplans.
+explain (analyze, verbose, costs off, summary off, timing off) execute mt_q2 (35);
+
+deallocate mt_q2;
+reset plan_cache_mode;
+
-- ensure initplan params properly prune partitions
explain (analyze, costs off, summary off, timing off) select * from ma_test where a >= (select min(b) from ma_test_p2) order by b;