From e2ee89a7e36641bd0386a8c7da5e5ebfebc78f92 Mon Sep 17 00:00:00 2001
From: amitlan <amitlangote09@gmail.com>
Date: Thu, 26 Jan 2023 21:10:19 +0900
Subject: [PATCH v1] Don't elide Append/MergeAppend if run-time pruning present

---
 src/backend/optimizer/plan/setrefs.c          | 27 +++---
 src/test/regress/expected/partition_prune.out | 87 ++++++++++++-------
 src/test/regress/sql/partition_prune.sql      |  8 ++
 3 files changed, 80 insertions(+), 42 deletions(-)

diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 85ba9d1ca1..4e582afb0a 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1708,13 +1708,14 @@ set_append_references(PlannerInfo *root,
 
 	/*
 	 * See if it's safe to get rid of the Append entirely.  For this to be
-	 * safe, there must be only one child plan and that child plan's parallel
-	 * awareness must match the Append's.  The reason for the latter is that
-	 * if the Append is parallel aware and the child is not, then the calling
-	 * plan may execute the non-parallel aware child multiple times.  (If you
+	 * safe, there must be only one child plan and no run-time pruning info
+	 * must have been set.  Also, the only child plan's parallel awareness
+	 * must match the Append's.  The reason for the latter is that if the
+	 * Append is parallel aware and the child is not, then the calling plan
+	 * may execute the non-parallel aware child multiple times.  (If you
 	 * change these rules, update create_append_path to match.)
 	 */
-	if (list_length(aplan->appendplans) == 1)
+	if (list_length(aplan->appendplans) == 1 && aplan->part_prune_index < 0)
 	{
 		Plan	   *p = (Plan *) linitial(aplan->appendplans);
 
@@ -1773,15 +1774,15 @@ set_mergeappend_references(PlannerInfo *root,
 	}
 
 	/*
-	 * See if it's safe to get rid of the MergeAppend entirely.  For this to
-	 * be safe, there must be only one child plan and that child plan's
-	 * parallel awareness must match the MergeAppend's.  The reason for the
-	 * latter is that if the MergeAppend is parallel aware and the child is
-	 * not, then the calling plan may execute the non-parallel aware child
-	 * multiple times.  (If you change these rules, update
-	 * create_merge_append_path to match.)
+	 * See if it's safe to get rid of the MergeAppend entirely.  For this to be
+	 * safe, there must be only one child plan and no run-time pruning info
+	 * must have been set.  Also, the only child plan's parallel awareness must
+	 * match the MergeAppend's.  The reason for the latter is that if the
+	 * MergeAppend is parallel aware and the child is not, then the calling
+	 * plan may execute the non-parallel aware child multiple times.  (If you
+	 * change these rules, update create_merge_append_path to match.)
 	 */
-	if (list_length(mplan->mergeplans) == 1)
+	if (list_length(mplan->mergeplans) == 1 && mplan->part_prune_index < 0)
 	{
 		Plan	   *p = (Plan *) linitial(mplan->mergeplans);
 
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 7555764c77..9554559215 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -1935,6 +1935,30 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh
 (13 rows)
 
 rollback;
+-- Test the case where an Append with only one run-time prunable partition
+-- must not be elided
+explain (analyze, costs off, summary off, timing off)
+	select * from list_part where a > 3 and a = (select 4);
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Append (actual rows=1 loops=1)
+   InitPlan 1 (returns $0)
+     ->  Result (actual rows=1 loops=1)
+   ->  Seq Scan on list_part4 list_part_1 (actual rows=1 loops=1)
+         Filter: ((a > 3) AND (a = $0))
+(5 rows)
+
+explain (analyze, costs off, summary off, timing off)
+	select * from list_part where a > 3 and a = (select 5);
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   InitPlan 1 (returns $0)
+     ->  Result (actual rows=1 loops=1)
+   ->  Seq Scan on list_part4 list_part_1 (never executed)
+         Filter: ((a > 3) AND (a = $0))
+(5 rows)
+
 drop table list_part;
 -- Parallel append
 -- Parallel queries won't necessarily get as many workers as the planner
@@ -2791,11 +2815,12 @@ prepare part_abc_q1 (int, int, int) as
 select * from part_abc where a = $1 and b = $2 and c = $3;
 -- Single partition should be scanned.
 explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3);
-                        QUERY PLAN                        
-----------------------------------------------------------
- Seq Scan on part_abc_p1 part_abc (actual rows=0 loops=1)
-   Filter: ((a = $1) AND (b = $2) AND (c = $3))
-(2 rows)
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   ->  Seq Scan on part_abc_p1 part_abc_1 (actual rows=0 loops=1)
+         Filter: ((a = $1) AND (b = $2) AND (c = $3))
+(3 rows)
 
 deallocate part_abc_q1;
 drop table part_abc;
@@ -3609,13 +3634,14 @@ create table listp2 partition of listp for values in(2) partition by list(b);
 create table listp2_10 partition of listp2 for values in (10);
 explain (analyze, costs off, summary off, timing off)
 select * from listp where a = (select 2) and b <> 10;
-                    QUERY PLAN                    
---------------------------------------------------
- Seq Scan on listp1 listp (actual rows=0 loops=1)
-   Filter: ((b <> 10) AND (a = $0))
+                    QUERY PLAN                     
+---------------------------------------------------
+ Append (actual rows=0 loops=1)
    InitPlan 1 (returns $0)
-     ->  Result (never executed)
-(4 rows)
+     ->  Result (actual rows=1 loops=1)
+   ->  Seq Scan on listp1 listp_1 (never executed)
+         Filter: ((b <> 10) AND (a = $0))
+(5 rows)
 
 --
 -- check that a partition directly accessed in a query is excluded with
@@ -3674,8 +3700,8 @@ alter table listp_12_1 set (parallel_workers = 0);
 -- Ensure that listp_12_2 is not scanned.  (The nested Append is not seen in
 -- the plan as it's pulled in setref.c due to having just a single subnode).
 select explain_parallel_append('select * from listp where a = (select 1);');
-                       explain_parallel_append                        
-----------------------------------------------------------------------
+                          explain_parallel_append                           
+----------------------------------------------------------------------------
  Gather (actual rows=N loops=N)
    Workers Planned: 2
    Params Evaluated: $0
@@ -3683,11 +3709,12 @@ select explain_parallel_append('select * from listp where a = (select 1);');
    InitPlan 1 (returns $0)
      ->  Result (actual rows=N loops=N)
    ->  Parallel Append (actual rows=N loops=N)
-         ->  Seq Scan on listp_12_1 listp_1 (actual rows=N loops=N)
-               Filter: (a = $0)
-         ->  Parallel Seq Scan on listp_12_2 listp_2 (never executed)
-               Filter: (a = $0)
-(11 rows)
+         ->  Parallel Append (actual rows=N loops=N)
+               ->  Seq Scan on listp_12_1 listp_2 (actual rows=N loops=N)
+                     Filter: (a = $0)
+               ->  Parallel Seq Scan on listp_12_2 listp_3 (never executed)
+                     Filter: (a = $0)
+(12 rows)
 
 -- Like the above but throw some more complexity at the planner by adding
 -- a UNION ALL.  We expect both sides of the union not to scan the
@@ -3696,8 +3723,8 @@ select explain_parallel_append(
 'select * from listp where a = (select 1)
   union all
 select * from listp where a = (select 2);');
-                              explain_parallel_append                              
------------------------------------------------------------------------------------
+                                 explain_parallel_append                                 
+-----------------------------------------------------------------------------------------
  Append (actual rows=N loops=N)
    ->  Gather (actual rows=N loops=N)
          Workers Planned: 2
@@ -3706,10 +3733,11 @@ select * from listp where a = (select 2);');
          InitPlan 1 (returns $0)
            ->  Result (actual rows=N loops=N)
          ->  Parallel Append (actual rows=N loops=N)
-               ->  Seq Scan on listp_12_1 listp_1 (actual rows=N loops=N)
-                     Filter: (a = $0)
-               ->  Parallel Seq Scan on listp_12_2 listp_2 (never executed)
-                     Filter: (a = $0)
+               ->  Parallel Append (actual rows=N loops=N)
+                     ->  Seq Scan on listp_12_1 listp_2 (actual rows=N loops=N)
+                           Filter: (a = $0)
+                     ->  Parallel Seq Scan on listp_12_2 listp_3 (never executed)
+                           Filter: (a = $0)
    ->  Gather (actual rows=N loops=N)
          Workers Planned: 2
          Params Evaluated: $1
@@ -3717,11 +3745,12 @@ select * from listp where a = (select 2);');
          InitPlan 2 (returns $1)
            ->  Result (actual rows=N loops=N)
          ->  Parallel Append (actual rows=N loops=N)
-               ->  Seq Scan on listp_12_1 listp_4 (never executed)
-                     Filter: (a = $1)
-               ->  Parallel Seq Scan on listp_12_2 listp_5 (actual rows=N loops=N)
-                     Filter: (a = $1)
-(23 rows)
+               ->  Parallel Append (actual rows=N loops=N)
+                     ->  Seq Scan on listp_12_1 listp_6 (never executed)
+                           Filter: (a = $1)
+                     ->  Parallel Seq Scan on listp_12_2 listp_7 (actual rows=N loops=N)
+                           Filter: (a = $1)
+(25 rows)
 
 drop table listp;
 reset parallel_tuple_cost;
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index d70bd8610c..560aa0ccc0 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -439,6 +439,14 @@ explain (analyze, costs off, summary off, timing off) select * from list_part wh
 
 rollback;
 
+-- Test the case where an Append with only one run-time prunable partition
+-- must not be elided
+explain (analyze, costs off, summary off, timing off)
+	select * from list_part where a > 3 and a = (select 4);
+explain (analyze, costs off, summary off, timing off)
+	select * from list_part where a > 3 and a = (select 5);
+
+
 drop table list_part;
 
 -- Parallel append
-- 
2.35.3

