diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index aabb024..f6a9fd2 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -1093,3 +1093,483 @@ explain (costs off) select * from boolpart where a is not unknown;
 (7 rows)
 
 drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart;
+--
+-- Test runtime partitioning
+--
+create table ab (a int not null, b int not null) partition by list(a);
+create table ab_a2 partition of ab for values in(2) partition by list (b);
+create table ab_a2_b1 partition of ab_a2 for values in (1);
+create table ab_a2_b2 partition of ab_a2 for values in (2);
+create table ab_a2_b3 partition of ab_a2 for values in (3);
+create table ab_a1 partition of ab for values in(1) partition by list (b);
+create table ab_a1_b1 partition of ab_a1 for values in (1);
+create table ab_a1_b2 partition of ab_a1 for values in (2);
+create table ab_a1_b3 partition of ab_a1 for values in (3);
+create table ab_a3 partition of ab for values in(3) partition by list (b);
+create table ab_a3_b1 partition of ab_a3 for values in (1);
+create table ab_a3_b2 partition of ab_a3 for values in (2);
+create table ab_a3_b3 partition of ab_a3 for values in (3);
+prepare ab_q1 (int, int, int) as select * from ab where a BETWEEN $1 and $2 AND b <= $3;
+execute ab_q1 (1, 8, 3);
+ a | b 
+---+---
+(0 rows)
+
+execute ab_q1 (1, 8, 3);
+ a | b 
+---+---
+(0 rows)
+
+execute ab_q1 (1, 8, 3);
+ a | b 
+---+---
+(0 rows)
+
+execute ab_q1 (1, 8, 3);
+ a | b 
+---+---
+(0 rows)
+
+execute ab_q1 (1, 8, 3);
+ a | b 
+---+---
+(0 rows)
+
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3);
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   Runtime Partition Pruning: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b3 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b3 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b3 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+(20 rows)
+
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3);
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   Runtime Partition Pruning: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a1_b3 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a2_b3 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+   ->  Seq Scan on ab_a3_b3 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b <= $3))
+(20 rows)
+
+-- runtime pruning after optimizer pruning
+deallocate ab_q1;
+prepare ab_q1 (int, int) as select a from ab where a BETWEEN $1 and $2 AND b < 3;
+execute ab_q1 (1, 8);
+ a 
+---
+(0 rows)
+
+execute ab_q1 (1, 8);
+ a 
+---
+(0 rows)
+
+execute ab_q1 (1, 8);
+ a 
+---
+(0 rows)
+
+execute ab_q1 (1, 8);
+ a 
+---
+(0 rows)
+
+execute ab_q1 (1, 8);
+ a 
+---
+(0 rows)
+
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2);
+                       QUERY PLAN                       
+--------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   Runtime Partition Pruning: ((a >= $1) AND (a <= $2))
+   ->  Seq Scan on ab_a1_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a1_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a3_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a3_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+(14 rows)
+
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4);
+                       QUERY PLAN                       
+--------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   Runtime Partition Pruning: ((a >= $1) AND (a <= $2))
+   ->  Seq Scan on ab_a1_b1 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a1_b2 (never executed)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a3_b1 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+   ->  Seq Scan on ab_a3_b2 (actual rows=0 loops=1)
+         Filter: ((a >= $1) AND (a <= $2) AND (b < 3))
+(14 rows)
+
+-- join
+DROP TABLE IF EXISTS tbl1;
+NOTICE:  table "tbl1" does not exist, skipping
+CREATE TABLE tbl1(col1 int);
+INSERT INTO tbl1 VALUES (501), (505);
+--basic table
+DROP TABLE IF EXISTS tprt;
+NOTICE:  table "tprt" does not exist, skipping
+CREATE TABLE tprt (col1 int) PARTITION BY range(col1);
+CREATE TABLE tprt_1 PARTITION OF tprt FOR VALUES FROM (1) TO (501);
+CREATE TABLE tprt_2 PARTITION OF tprt FOR VALUES FROM (501) TO (1001);
+CREATE TABLE tprt_3 PARTITION OF tprt FOR VALUES FROM (1001) TO (2001);
+CREATE TABLE tprt_4 PARTITION OF tprt FOR VALUES FROM (2001) TO (3001);
+CREATE TABLE tprt_5 PARTITION OF tprt FOR VALUES FROM (3001) TO (4001);
+CREATE TABLE tprt_6 PARTITION OF tprt FOR VALUES FROM (4001) TO (5001);
+CREATE INDEX tprt1_idx ON tprt_1 (col1);
+CREATE INDEX tprt2_idx ON tprt_2 (col1);
+CREATE INDEX tprt3_idx ON tprt_3 (col1);
+CREATE INDEX tprt4_idx ON tprt_4 (col1);
+CREATE INDEX tprt5_idx ON tprt_5 (col1);
+CREATE INDEX tprt6_idx ON tprt_6 (col1);
+INSERT INTO tprt VALUES (10), (20), (501), (502), (505), (1001), (4500);
+SET enable_hashjoin = OFF;
+SET enable_mergejoin = OFF;
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=6 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=2 loops=1)
+   ->  Append (actual rows=3 loops=2)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 > col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (actual rows=2 loops=2)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 4
+         ->  Index Only Scan using tprt2_idx on tprt_2 (actual rows=2 loops=1)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 2
+         ->  Index Only Scan using tprt3_idx on tprt_3 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+(22 rows)
+
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=2 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=2 loops=1)
+   ->  Append (actual rows=1 loops=2)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 = col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt2_idx on tprt_2 (actual rows=1 loops=2)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 2
+         ->  Index Only Scan using tprt3_idx on tprt_3 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+(22 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+  501 |   10
+  501 |   20
+  505 |   10
+  505 |   20
+  505 |  501
+  505 |  502
+(6 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+  501 |  501
+  505 |  505
+(2 rows)
+
+--multiple partitions
+INSERT INTO tbl1 VALUES (1001), (1010);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=17 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=4 loops=1)
+   ->  Append (actual rows=4 loops=4)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 > col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (actual rows=2 loops=4)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 8
+         ->  Index Only Scan using tprt2_idx on tprt_2 (actual rows=3 loops=3)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 8
+         ->  Index Only Scan using tprt3_idx on tprt_3 (actual rows=1 loops=1)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 1
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (never executed)
+               Index Cond: (col1 < tbl1.col1)
+               Heap Fetches: 0
+(22 rows)
+
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=3 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=4 loops=1)
+   ->  Append (actual rows=1 loops=4)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 = col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt2_idx on tprt_2 (actual rows=1 loops=2)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 2
+         ->  Index Only Scan using tprt3_idx on tprt_3 (actual rows=0 loops=2)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 1
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+(22 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+  501 |   10
+  501 |   20
+  505 |   10
+  505 |   20
+  505 |  501
+  505 |  502
+ 1001 |   10
+ 1001 |   20
+ 1001 |  501
+ 1001 |  502
+ 1001 |  505
+ 1010 |   10
+ 1010 |   20
+ 1010 |  501
+ 1010 |  502
+ 1010 |  505
+ 1010 | 1001
+(17 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+  501 |  501
+  505 |  505
+ 1001 | 1001
+(3 rows)
+
+--last partition
+DELETE FROM tbl1;
+INSERT INTO tbl1 VALUES (4400);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 < tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=1 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=1 loops=1)
+   ->  Append (actual rows=1 loops=1)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 < col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (never executed)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt2_idx on tprt_2 (never executed)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt3_idx on tprt_3 (never executed)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (actual rows=1 loops=1)
+               Index Cond: (col1 > tbl1.col1)
+               Heap Fetches: 1
+(22 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 < tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+ 4400 | 4500
+(1 row)
+
+--no partition
+DELETE FROM tbl1;
+INSERT INTO tbl1 VALUES (10000);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Nested Loop (actual rows=0 loops=1)
+   ->  Seq Scan on tbl1 (actual rows=1 loops=1)
+   ->  Append (actual rows=0 loops=1)
+         Runtime Partition Pruning Join Filter: (tbl1.col1 = col1)
+         ->  Index Only Scan using tprt1_idx on tprt_1 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt2_idx on tprt_2 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt3_idx on tprt_3 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt4_idx on tprt_4 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt5_idx on tprt_5 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+         ->  Index Only Scan using tprt6_idx on tprt_6 (never executed)
+               Index Cond: (col1 = tbl1.col1)
+               Heap Fetches: 0
+(22 rows)
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+ col1 | col1 
+------+------
+(0 rows)
+
+-- parallel append
+deallocate ab_q1;
+prepare ab_q1 (int, int) as select avg(a) from ab where a BETWEEN $1 and $2 AND b < 4;
+-- encourage use of parallel plans
+set parallel_setup_cost=0;
+set parallel_tuple_cost=0;
+set min_parallel_table_scan_size=0;
+set max_parallel_workers_per_gather=2;
+execute ab_q1 (1, 8);
+ avg 
+-----
+    
+(1 row)
+
+execute ab_q1 (1, 8);
+ avg 
+-----
+    
+(1 row)
+
+execute ab_q1 (1, 8);
+ avg 
+-----
+    
+(1 row)
+
+execute ab_q1 (1, 8);
+ avg 
+-----
+    
+(1 row)
+
+execute ab_q1 (1, 8);
+ avg 
+-----
+    
+(1 row)
+
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2);
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Finalize Aggregate (actual rows=1 loops=1)
+   ->  Gather (actual rows=3 loops=1)
+         Workers Planned: 2
+         Workers Launched: 2
+         ->  Partial Aggregate (actual rows=1 loops=3)
+               ->  Parallel Append (actual rows=0 loops=3)
+                     Runtime Partition Pruning: ((a >= $1) AND (a <= $2))
+                     ->  Parallel Seq Scan on ab_a1_b1 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a1_b2 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a1_b3 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a2_b3 (actual rows=0 loops=1)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a3_b1 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a3_b2 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+                     ->  Parallel Seq Scan on ab_a3_b3 (never executed)
+                           Filter: ((a >= $1) AND (a <= $2) AND (b < 4))
+(25 rows)
+
+drop table if exists ab;
diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql
index 514f8e5..2f92e52 100644
--- a/src/test/regress/sql/partition_prune.sql
+++ b/src/test/regress/sql/partition_prune.sql
@@ -153,3 +153,116 @@ explain (costs off) select * from boolpart where a is unknown;
 explain (costs off) select * from boolpart where a is not unknown;
 
 drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart;
+
+--
+-- Test runtime partitioning
+--
+create table ab (a int not null, b int not null) partition by list(a);
+create table ab_a2 partition of ab for values in(2) partition by list (b);
+create table ab_a2_b1 partition of ab_a2 for values in (1);
+create table ab_a2_b2 partition of ab_a2 for values in (2);
+create table ab_a2_b3 partition of ab_a2 for values in (3);
+create table ab_a1 partition of ab for values in(1) partition by list (b);
+create table ab_a1_b1 partition of ab_a1 for values in (1);
+create table ab_a1_b2 partition of ab_a1 for values in (2);
+create table ab_a1_b3 partition of ab_a1 for values in (3);
+create table ab_a3 partition of ab for values in(3) partition by list (b);
+create table ab_a3_b1 partition of ab_a3 for values in (1);
+create table ab_a3_b2 partition of ab_a3 for values in (2);
+create table ab_a3_b3 partition of ab_a3 for values in (3);
+
+prepare ab_q1 (int, int, int) as select * from ab where a BETWEEN $1 and $2 AND b <= $3;
+
+execute ab_q1 (1, 8, 3);
+execute ab_q1 (1, 8, 3);
+execute ab_q1 (1, 8, 3);
+execute ab_q1 (1, 8, 3);
+execute ab_q1 (1, 8, 3);
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2, 3);
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (1, 2, 3);
+
+-- runtime pruning after optimizer pruning
+deallocate ab_q1;
+prepare ab_q1 (int, int) as select a from ab where a BETWEEN $1 and $2 AND b < 3;
+
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2);
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4);
+
+-- join
+DROP TABLE IF EXISTS tbl1;
+CREATE TABLE tbl1(col1 int);
+INSERT INTO tbl1 VALUES (501), (505);
+
+--basic table
+
+DROP TABLE IF EXISTS tprt;
+CREATE TABLE tprt (col1 int) PARTITION BY range(col1);
+CREATE TABLE tprt_1 PARTITION OF tprt FOR VALUES FROM (1) TO (501);
+CREATE TABLE tprt_2 PARTITION OF tprt FOR VALUES FROM (501) TO (1001);
+CREATE TABLE tprt_3 PARTITION OF tprt FOR VALUES FROM (1001) TO (2001);
+CREATE TABLE tprt_4 PARTITION OF tprt FOR VALUES FROM (2001) TO (3001);
+CREATE TABLE tprt_5 PARTITION OF tprt FOR VALUES FROM (3001) TO (4001);
+CREATE TABLE tprt_6 PARTITION OF tprt FOR VALUES FROM (4001) TO (5001);
+
+CREATE INDEX tprt1_idx ON tprt_1 (col1);
+CREATE INDEX tprt2_idx ON tprt_2 (col1);
+CREATE INDEX tprt3_idx ON tprt_3 (col1);
+CREATE INDEX tprt4_idx ON tprt_4 (col1);
+CREATE INDEX tprt5_idx ON tprt_5 (col1);
+CREATE INDEX tprt6_idx ON tprt_6 (col1);
+
+INSERT INTO tprt VALUES (10), (20), (501), (502), (505), (1001), (4500);
+
+SET enable_hashjoin = OFF;
+SET enable_mergejoin = OFF;
+
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1;
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+
+--multiple partitions
+INSERT INTO tbl1 VALUES (1001), (1010);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1;
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 > tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+
+--last partition
+DELETE FROM tbl1;
+INSERT INTO tbl1 VALUES (4400);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 < tprt.col1;
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 < tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+
+--no partition
+DELETE FROM tbl1;
+INSERT INTO tbl1 VALUES (10000);
+explain (analyze, costs off, summary off, timing off) SELECT * FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1;
+SELECT tbl1.col1, tprt.col1 FROM tbl1 JOIN tprt ON tbl1.col1 = tprt.col1 ORDER BY tbl1.col1, tprt.col1;
+
+
+-- parallel append
+deallocate ab_q1;
+prepare ab_q1 (int, int) as select avg(a) from ab where a BETWEEN $1 and $2 AND b < 4;
+
+-- encourage use of parallel plans
+set parallel_setup_cost=0;
+set parallel_tuple_cost=0;
+set min_parallel_table_scan_size=0;
+set max_parallel_workers_per_gather=2;
+
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+execute ab_q1 (1, 8);
+explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2);
+
+drop table if exists ab;
