From 7a458b66cea826cf4a7e4fd7a44598c902787075 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Fri, 10 Feb 2017 14:18:19 +0530
Subject: [PATCH 13/14] Multi-level partition-wise join tests.

---
 .../expected/multi_level_partition_join.out        |  687 ++++++++++++++++++++
 src/test/regress/parallel_schedule                 |    2 +-
 src/test/regress/serial_schedule                   |    1 +
 .../regress/sql/multi_level_partition_join.sql     |   95 +++
 4 files changed, 784 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/multi_level_partition_join.out
 create mode 100644 src/test/regress/sql/multi_level_partition_join.sql

diff --git a/src/test/regress/expected/multi_level_partition_join.out b/src/test/regress/expected/multi_level_partition_join.out
new file mode 100644
index 0000000..97b1e79
--- /dev/null
+++ b/src/test/regress/expected/multi_level_partition_join.out
@@ -0,0 +1,687 @@
+-- Encourage partition-wise join plans.
+SET partition_wise_plan_weight TO 0.1;
+--
+-- multi-leveled partitions
+--
+CREATE TABLE prt1_l (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_l_p2 PARTITION OF prt1_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
+CREATE TABLE prt1_l_p2_p1 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0250') TO ('0400');
+CREATE TABLE prt1_l_p2_p2 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0400') TO ('0500');
+CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (b);
+CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (500) TO (550);
+CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (550) TO (600);
+INSERT INTO prt1_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_l;
+ANALYZE prt1_l_p1;
+ANALYZE prt1_l_p2;
+ANALYZE prt1_l_p2_p1;
+ANALYZE prt1_l_p2_p2;
+ANALYZE prt1_l_p3;
+ANALYZE prt1_l_p3_p1;
+ANALYZE prt1_l_p3_p2;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_l AS SELECT * FROM prt1_l;
+CREATE TABLE prt2_l (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_l_p2 PARTITION OF prt2_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
+CREATE TABLE prt2_l_p2_p1 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0250') TO ('0400');
+CREATE TABLE prt2_l_p2_p2 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0400') TO ('0500');
+CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (a);
+CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (500) TO (525);
+CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (525) TO (600);
+INSERT INTO prt2_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_l;
+ANALYZE prt2_l_p1;
+ANALYZE prt2_l_p2;
+ANALYZE prt2_l_p2_p1;
+ANALYZE prt2_l_p2_p2;
+ANALYZE prt2_l_p3;
+ANALYZE prt2_l_p3_p1;
+ANALYZE prt2_l_p3_p2;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_l AS SELECT * FROM prt2_l;
+-- inner join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Output: t1.a, t1.c, t2.b, t2.c
+               Hash Cond: ((t2.b = t1.a) AND ((t2.c)::text = (t1.c)::text))
+               ->  Seq Scan on public.prt2_l_p1 t2
+                     Output: t2.b, t2.c
+               ->  Hash
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
+                           Filter: ((t1.a % 25) = 0)
+         ->  Hash Join
+               Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
+               Hash Cond: ((t2_1.b = t1_1.a) AND ((t2_1.c)::text = (t1_1.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
+               ->  Hash
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+         ->  Hash Join
+               Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
+               Hash Cond: ((t2_2.b = t1_2.a) AND ((t2_2.c)::text = (t1_2.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
+               ->  Hash
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+         ->  Hash Join
+               Output: t1_3.a, t1_3.c, t2_3.b, t2_3.c
+               Hash Cond: ((t2_3.b = t1_3.a) AND ((t2_3.c)::text = (t1_3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt2_l_p3 t2_3
+                           Output: t2_3.b, t2_3.c
+                     ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                           Output: t2_4.b, t2_4.c
+                     ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                           Output: t2_5.b, t2_5.c
+               ->  Hash
+                     Output: t1_3.a, t1_3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+(56 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+ 150 | 0150 | 150 | 0150
+ 300 | 0300 | 300 | 0300
+ 450 | 0450 | 450 | 0450
+(4 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+ 150 | 0150 | 150 | 0150
+ 300 | 0300 | 300 | 0300
+ 450 | 0450 | 450 | 0450
+(4 rows)
+
+-- left join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c
+   Sort Key: t1.a, t2.b
+   ->  Append
+         ->  Hash Right Join
+               Output: t1.a, t1.c, t2.b, t2.c
+               Hash Cond: ((t2.b = t1.a) AND ((t2.c)::text = (t1.c)::text))
+               ->  Seq Scan on public.prt2_l_p1 t2
+                     Output: t2.b, t2.c
+               ->  Hash
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
+                           Filter: ((t1.a % 25) = 0)
+         ->  Hash Right Join
+               Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
+               Hash Cond: ((t2_1.b = t1_1.a) AND ((t2_1.c)::text = (t1_1.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
+               ->  Hash
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+         ->  Hash Right Join
+               Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
+               Hash Cond: ((t2_2.b = t1_2.a) AND ((t2_2.c)::text = (t1_2.c)::text))
+               ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
+               ->  Hash
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+         ->  Hash Right Join
+               Output: t1_3.a, t1_3.c, t2_3.b, t2_3.c
+               Hash Cond: ((t2_3.b = t1_3.a) AND ((t2_3.c)::text = (t1_3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt2_l_p3 t2_3
+                           Output: t2_3.b, t2_3.c
+                     ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                           Output: t2_4.b, t2_4.c
+                     ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                           Output: t2_5.b, t2_5.c
+               ->  Hash
+                     Output: t1_3.a, t1_3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+(56 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 | 150 | 0150
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+ 450 | 0450 | 450 | 0450
+ 500 | 0500 |     | 
+ 550 | 0550 |     | 
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 | 150 | 0150
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+ 450 | 0450 | 450 | 0450
+ 500 | 0500 |     | 
+ 550 | 0550 |     | 
+(12 rows)
+
+-- right join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+                                        QUERY PLAN                                        
+------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c
+   Sort Key: t1.a, t2.b
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t2.b, t2.c, t1.a, t1.c
+                     Hash Cond: ((t1.a = t2.b) AND ((t1.c)::text = (t2.c)::text))
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.c
+                     ->  Hash
+                           Output: t2.b, t2.c
+                           ->  Seq Scan on public.prt2_l_p1 t2
+                                 Output: t2.b, t2.c
+                                 Filter: ((t2.b % 25) = 0)
+               ->  Hash Right Join
+                     Output: t2_1.b, t2_1.c, t1_1.a, t1_1.c
+                     Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.c
+                     ->  Hash
+                           Output: t2_1.b, t2_1.c
+                           ->  Seq Scan on public.prt2_l_p2_p1 t2_1
+                                 Output: t2_1.b, t2_1.c
+                                 Filter: ((t2_1.b % 25) = 0)
+               ->  Hash Right Join
+                     Output: t2_2.b, t2_2.c, t1_2.a, t1_2.c
+                     Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                     ->  Hash
+                           Output: t2_2.b, t2_2.c
+                           ->  Seq Scan on public.prt2_l_p2_p2 t2_2
+                                 Output: t2_2.b, t2_2.c
+                                 Filter: ((t2_2.b % 25) = 0)
+               ->  Hash Right Join
+                     Output: t2_3.b, t2_3.c, t1_3.a, t1_3.c
+                     Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text))
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.c
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.c
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.c
+                     ->  Hash
+                           Output: t2_3.b, t2_3.c
+                           ->  Append
+                                 ->  Seq Scan on public.prt2_l_p3 t2_3
+                                       Output: t2_3.b, t2_3.c
+                                       Filter: ((t2_3.b % 25) = 0)
+                                 ->  Seq Scan on public.prt2_l_p3_p1 t2_4
+                                       Output: t2_4.b, t2_4.c
+                                       Filter: ((t2_4.b % 25) = 0)
+                                 ->  Seq Scan on public.prt2_l_p3_p2 t2_5
+                                       Output: t2_5.b, t2_5.c
+                                       Filter: ((t2_5.b % 25) = 0)
+(58 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+ 150 | 0150 | 150 | 0150
+ 300 | 0300 | 300 | 0300
+ 450 | 0450 | 450 | 0450
+     |      |  75 | 0075
+     |      | 225 | 0225
+     |      | 375 | 0375
+     |      | 525 | 0525
+(8 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+ 150 | 0150 | 150 | 0150
+ 300 | 0300 | 300 | 0300
+ 450 | 0450 | 450 | 0450
+     |      |  75 | 0075
+     |      | 225 | 0225
+     |      | 375 | 0375
+     |      | 525 | 0525
+(8 rows)
+
+-- full join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+                                                     QUERY PLAN                                                     
+--------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_l_p1.a, prt1_l_p1.c, prt2_l_p1.b, prt2_l_p1.c
+   Sort Key: prt1_l_p1.a, prt2_l_p1.b
+   ->  Append
+         ->  Hash Full Join
+               Output: prt1_l_p1.a, prt1_l_p1.c, prt2_l_p1.b, prt2_l_p1.c
+               Hash Cond: ((prt1_l_p1.a = prt2_l_p1.b) AND ((prt1_l_p1.c)::text = (prt2_l_p1.c)::text))
+               ->  Seq Scan on public.prt1_l_p1
+                     Output: prt1_l_p1.a, prt1_l_p1.c
+                     Filter: ((prt1_l_p1.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_l_p1.b, prt2_l_p1.c
+                     ->  Seq Scan on public.prt2_l_p1
+                           Output: prt2_l_p1.b, prt2_l_p1.c
+                           Filter: ((prt2_l_p1.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_l_p2_p1.a, prt1_l_p2_p1.c, prt2_l_p2_p1.b, prt2_l_p2_p1.c
+               Hash Cond: ((prt1_l_p2_p1.a = prt2_l_p2_p1.b) AND ((prt1_l_p2_p1.c)::text = (prt2_l_p2_p1.c)::text))
+               ->  Seq Scan on public.prt1_l_p2_p1
+                     Output: prt1_l_p2_p1.a, prt1_l_p2_p1.c
+                     Filter: ((prt1_l_p2_p1.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c
+                     ->  Seq Scan on public.prt2_l_p2_p1
+                           Output: prt2_l_p2_p1.b, prt2_l_p2_p1.c
+                           Filter: ((prt2_l_p2_p1.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_l_p2_p2.a, prt1_l_p2_p2.c, prt2_l_p2_p2.b, prt2_l_p2_p2.c
+               Hash Cond: ((prt1_l_p2_p2.a = prt2_l_p2_p2.b) AND ((prt1_l_p2_p2.c)::text = (prt2_l_p2_p2.c)::text))
+               ->  Seq Scan on public.prt1_l_p2_p2
+                     Output: prt1_l_p2_p2.a, prt1_l_p2_p2.c
+                     Filter: ((prt1_l_p2_p2.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c
+                     ->  Seq Scan on public.prt2_l_p2_p2
+                           Output: prt2_l_p2_p2.b, prt2_l_p2_p2.c
+                           Filter: ((prt2_l_p2_p2.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_l_p3.a, prt1_l_p3.c, prt2_l_p3.b, prt2_l_p3.c
+               Hash Cond: ((prt1_l_p3.a = prt2_l_p3.b) AND ((prt1_l_p3.c)::text = (prt2_l_p3.c)::text))
+               ->  Append
+                     ->  Seq Scan on public.prt1_l_p3
+                           Output: prt1_l_p3.a, prt1_l_p3.c
+                           Filter: ((prt1_l_p3.a % 25) = 0)
+                     ->  Seq Scan on public.prt1_l_p3_p1
+                           Output: prt1_l_p3_p1.a, prt1_l_p3_p1.c
+                           Filter: ((prt1_l_p3_p1.a % 25) = 0)
+                     ->  Seq Scan on public.prt1_l_p3_p2
+                           Output: prt1_l_p3_p2.a, prt1_l_p3_p2.c
+                           Filter: ((prt1_l_p3_p2.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_l_p3.b, prt2_l_p3.c
+                     ->  Append
+                           ->  Seq Scan on public.prt2_l_p3
+                                 Output: prt2_l_p3.b, prt2_l_p3.c
+                                 Filter: ((prt2_l_p3.b % 25) = 0)
+                           ->  Seq Scan on public.prt2_l_p3_p1
+                                 Output: prt2_l_p3_p1.b, prt2_l_p3_p1.c
+                                 Filter: ((prt2_l_p3_p1.b % 25) = 0)
+                           ->  Seq Scan on public.prt2_l_p3_p2
+                                 Output: prt2_l_p3_p2.b, prt2_l_p3_p2.c
+                                 Filter: ((prt2_l_p3_p2.b % 25) = 0)
+(62 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 | 150 | 0150
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+ 450 | 0450 | 450 | 0450
+ 500 | 0500 |     | 
+ 550 | 0550 |     | 
+     |      |  75 | 0075
+     |      | 225 | 0225
+     |      | 375 | 0375
+     |      | 525 | 0525
+(16 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l WHERE uprt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l WHERE uprt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 | 150 | 0150
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+ 450 | 0450 | 450 | 0450
+ 500 | 0500 |     | 
+ 550 | 0550 |     | 
+     |      |  75 | 0075
+     |      | 225 | 0225
+     |      | 375 | 0375
+     |      | 525 | 0525
+(16 rows)
+
+-- lateral partition-wise join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                                     QUERY PLAN                                                      
+---------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   Sort Key: t1.a
+   ->  Result
+         Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+         ->  Append
+               ->  Nested Loop Left Join
+                     Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a))
+                     ->  Seq Scan on public.prt1_l_p1 t1
+                           Output: t1.a, t1.b, t1.c
+                           Filter: ((t1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2.a, t2.c, t2.b, t3.a, LEAST(t1.a, t2.a, t3.a)
+                           Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
+                           ->  Seq Scan on public.prt2_l_p1 t3
+                                 Output: t3.a, t3.b, t3.c
+                           ->  Hash
+                                 Output: t2.a, t2.c, t2.b
+                                 ->  Seq Scan on public.prt1_l_p1 t2
+                                       Output: t2.a, t2.c, t2.b
+                                       Filter: ((t1.a = t2.a) AND ((t1.c)::text = (t2.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t2_1.c, t2_1.b, t3_1.a, (LEAST(t1_1.a, t2_1.a, t3_1.a))
+                     ->  Seq Scan on public.prt1_l_p2_p1 t1_1
+                           Output: t1_1.a, t1_1.b, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_1.a, t2_1.c, t2_1.b, t3_1.a, LEAST(t1_1.a, t2_1.a, t3_1.a)
+                           Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
+                           ->  Seq Scan on public.prt2_l_p2_p1 t3_1
+                                 Output: t3_1.a, t3_1.b, t3_1.c
+                           ->  Hash
+                                 Output: t2_1.a, t2_1.c, t2_1.b
+                                 ->  Seq Scan on public.prt1_l_p2_p1 t2_1
+                                       Output: t2_1.a, t2_1.c, t2_1.b
+                                       Filter: ((t1_1.a = t2_1.a) AND ((t1_1.c)::text = (t2_1.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t2_2.c, t2_2.b, t3_2.a, (LEAST(t1_2.a, t2_2.a, t3_2.a))
+                     ->  Seq Scan on public.prt1_l_p2_p2 t1_2
+                           Output: t1_2.a, t1_2.b, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_2.a, t2_2.c, t2_2.b, t3_2.a, LEAST(t1_2.a, t2_2.a, t3_2.a)
+                           Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
+                           ->  Seq Scan on public.prt2_l_p2_p2 t3_2
+                                 Output: t3_2.a, t3_2.b, t3_2.c
+                           ->  Hash
+                                 Output: t2_2.a, t2_2.c, t2_2.b
+                                 ->  Seq Scan on public.prt1_l_p2_p2 t2_2
+                                       Output: t2_2.a, t2_2.c, t2_2.b
+                                       Filter: ((t1_2.a = t2_2.a) AND ((t1_2.c)::text = (t2_2.c)::text))
+               ->  Nested Loop Left Join
+                     Output: t1_3.a, t1_3.b, t1_3.c, t2_3.a, t2_3.c, t2_3.b, t3_3.a, (LEAST(t1_3.a, t2_3.a, t3_3.a))
+                     ->  Append
+                           ->  Seq Scan on public.prt1_l_p3 t1_3
+                                 Output: t1_3.a, t1_3.b, t1_3.c
+                                 Filter: ((t1_3.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p1 t1_4
+                                 Output: t1_4.a, t1_4.b, t1_4.c
+                                 Filter: ((t1_4.a % 25) = 0)
+                           ->  Seq Scan on public.prt1_l_p3_p2 t1_5
+                                 Output: t1_5.a, t1_5.b, t1_5.c
+                                 Filter: ((t1_5.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_3.a, t2_3.c, t2_3.b, t3_3.a, LEAST(t1_3.a, t2_3.a, t3_3.a)
+                           Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
+                           ->  Append
+                                 ->  Seq Scan on public.prt2_l_p3 t3_3
+                                       Output: t3_3.a, t3_3.b, t3_3.c
+                                 ->  Seq Scan on public.prt2_l_p3_p1 t3_4
+                                       Output: t3_4.a, t3_4.b, t3_4.c
+                                 ->  Seq Scan on public.prt2_l_p3_p2 t3_5
+                                       Output: t3_5.a, t3_5.b, t3_5.c
+                           ->  Hash
+                                 Output: t2_3.a, t2_3.c, t2_3.b
+                                 ->  Append
+                                       ->  Seq Scan on public.prt1_l_p3 t2_3
+                                             Output: t2_3.a, t2_3.c, t2_3.b
+                                             Filter: ((t1_3.a = t2_3.a) AND ((t1_3.c)::text = (t2_3.c)::text))
+                                       ->  Seq Scan on public.prt1_l_p3_p1 t2_4
+                                             Output: t2_4.a, t2_4.c, t2_4.b
+                                             Filter: ((t1_3.a = t2_4.a) AND ((t1_3.c)::text = (t2_4.c)::text))
+                                       ->  Seq Scan on public.prt1_l_p3_p2 t2_5
+                                             Output: t2_5.a, t2_5.c, t2_5.b
+                                             Filter: ((t1_3.a = t2_5.a) AND ((t1_3.c)::text = (t2_5.c)::text))
+(85 rows)
+
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+-- lateral references with clauses without equi-join on partition key
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                             QUERY PLAN                                              
+-----------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   Sort Key: t1.a
+   ->  Nested Loop Left Join
+         Output: t1.a, t1.b, t1.c, t2.a, t2.c, t2.b, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+         ->  Append
+               ->  Seq Scan on public.prt1_l t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p1 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2_p1 t1_3
+                     Output: t1_3.a, t1_3.b, t1_3.c
+                     Filter: ((t1_3.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p2_p2 t1_4
+                     Output: t1_4.a, t1_4.b, t1_4.c
+                     Filter: ((t1_4.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3 t1_5
+                     Output: t1_5.a, t1_5.b, t1_5.c
+                     Filter: ((t1_5.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3_p1 t1_6
+                     Output: t1_6.a, t1_6.b, t1_6.c
+                     Filter: ((t1_6.a % 25) = 0)
+               ->  Seq Scan on public.prt1_l_p3_p2 t1_7
+                     Output: t1_7.a, t1_7.b, t1_7.c
+                     Filter: ((t1_7.a % 25) = 0)
+         ->  Append
+               ->  Hash Join
+                     Output: t2.a, t2.c, t2.b, t3.a, LEAST(t1.a, t2.a, t3.a)
+                     Hash Cond: ((t3.b = t2.a) AND ((t3.c)::text = (t2.c)::text))
+                     ->  Seq Scan on public.prt2_l_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t2.a, t2.c, t2.b
+                           ->  Seq Scan on public.prt1_l_p1 t2
+                                 Output: t2.a, t2.c, t2.b
+                                 Filter: ((t1.b = t2.a) AND ((t1.c)::text = (t2.c)::text))
+               ->  Hash Join
+                     Output: t2_1.a, t2_1.c, t2_1.b, t3_1.a, LEAST(t1.a, t2_1.a, t3_1.a)
+                     Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
+                     ->  Seq Scan on public.prt2_l_p2_p1 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t2_1.a, t2_1.c, t2_1.b
+                           ->  Seq Scan on public.prt1_l_p2_p1 t2_1
+                                 Output: t2_1.a, t2_1.c, t2_1.b
+                                 Filter: ((t1.b = t2_1.a) AND ((t1.c)::text = (t2_1.c)::text))
+               ->  Hash Join
+                     Output: t2_2.a, t2_2.c, t2_2.b, t3_2.a, LEAST(t1.a, t2_2.a, t3_2.a)
+                     Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
+                     ->  Seq Scan on public.prt2_l_p2_p2 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t2_2.a, t2_2.c, t2_2.b
+                           ->  Seq Scan on public.prt1_l_p2_p2 t2_2
+                                 Output: t2_2.a, t2_2.c, t2_2.b
+                                 Filter: ((t1.b = t2_2.a) AND ((t1.c)::text = (t2_2.c)::text))
+               ->  Hash Join
+                     Output: t2_3.a, t2_3.c, t2_3.b, t3_3.a, LEAST(t1.a, t2_3.a, t3_3.a)
+                     Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
+                     ->  Append
+                           ->  Seq Scan on public.prt2_l_p3 t3_3
+                                 Output: t3_3.a, t3_3.b, t3_3.c
+                           ->  Seq Scan on public.prt2_l_p3_p1 t3_4
+                                 Output: t3_4.a, t3_4.b, t3_4.c
+                           ->  Seq Scan on public.prt2_l_p3_p2 t3_5
+                                 Output: t3_5.a, t3_5.b, t3_5.c
+                     ->  Hash
+                           Output: t2_3.a, t2_3.c, t2_3.b
+                           ->  Append
+                                 ->  Seq Scan on public.prt1_l_p3 t2_3
+                                       Output: t2_3.a, t2_3.c, t2_3.b
+                                       Filter: ((t1.b = t2_3.a) AND ((t1.c)::text = (t2_3.c)::text))
+                                 ->  Seq Scan on public.prt1_l_p3_p1 t2_4
+                                       Output: t2_4.a, t2_4.c, t2_4.b
+                                       Filter: ((t1.b = t2_4.a) AND ((t1.c)::text = (t2_4.c)::text))
+                                 ->  Seq Scan on public.prt1_l_p3_p2 t2_5
+                                       Output: t2_5.a, t2_5.c, t2_5.b
+                                       Filter: ((t1.b = t2_5.a) AND ((t1.c)::text = (t2_5.c)::text))
+(83 rows)
+
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t2c  | t2b | t3a | least 
+-----+-----+------+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |      |     |     |      
+ 100 | 100 | 0100 |     |      |     |     |      
+ 150 | 150 | 0150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |      |     |     |      
+ 250 | 250 | 0250 |     |      |     |     |      
+ 300 | 300 | 0300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |      |     |     |      
+ 400 | 400 | 0400 |     |      |     |     |      
+ 450 | 450 | 0450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |      |     |     |      
+ 550 | 550 | 0550 |     |      |     |     |      
+(12 rows)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index ac38f50..8d28203 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -103,7 +103,7 @@ test: publication subscription
 # ----------
 # Another group of parallel tests
 # ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb json_encoding indirect_toast equivclass partition_join
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb json_encoding indirect_toast equivclass partition_join multi_level_partition_join
 # ----------
 # Another group of parallel tests
 # NB: temp.sql does a reconnect which transiently uses 2 connections,
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 1bf98a4..14df5ee 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -173,3 +173,4 @@ test: xml
 test: event_trigger
 test: stats
 test: partition_join
+test: multi_level_partition_join
diff --git a/src/test/regress/sql/multi_level_partition_join.sql b/src/test/regress/sql/multi_level_partition_join.sql
new file mode 100644
index 0000000..821c095
--- /dev/null
+++ b/src/test/regress/sql/multi_level_partition_join.sql
@@ -0,0 +1,95 @@
+-- Encourage partition-wise join plans.
+SET partition_wise_plan_weight TO 0.1;
+
+--
+-- multi-leveled partitions
+--
+CREATE TABLE prt1_l (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_l_p2 PARTITION OF prt1_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
+CREATE TABLE prt1_l_p2_p1 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0250') TO ('0400');
+CREATE TABLE prt1_l_p2_p2 PARTITION OF prt1_l_p2 FOR VALUES FROM ('0400') TO ('0500');
+CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (b);
+CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (500) TO (550);
+CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (550) TO (600);
+INSERT INTO prt1_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_l;
+ANALYZE prt1_l_p1;
+ANALYZE prt1_l_p2;
+ANALYZE prt1_l_p2_p1;
+ANALYZE prt1_l_p2_p2;
+ANALYZE prt1_l_p3;
+ANALYZE prt1_l_p3_p1;
+ANALYZE prt1_l_p3_p2;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_l AS SELECT * FROM prt1_l;
+
+CREATE TABLE prt2_l (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_l_p2 PARTITION OF prt2_l FOR VALUES FROM (250) TO (500) PARTITION BY RANGE (c);
+CREATE TABLE prt2_l_p2_p1 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0250') TO ('0400');
+CREATE TABLE prt2_l_p2_p2 PARTITION OF prt2_l_p2 FOR VALUES FROM ('0400') TO ('0500');
+CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (a);
+CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (500) TO (525);
+CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (525) TO (600);
+INSERT INTO prt2_l SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_l;
+ANALYZE prt2_l_p1;
+ANALYZE prt2_l_p2;
+ANALYZE prt2_l_p2_p1;
+ANALYZE prt2_l_p2_p2;
+ANALYZE prt2_l_p3;
+ANALYZE prt2_l_p3_p1;
+ANALYZE prt2_l_p3_p2;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_l AS SELECT * FROM prt2_l;
+
+-- inner join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1, uprt2_l t2 WHERE t1.a = t2.b AND t1.c = t2.c AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- left join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 LEFT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- right join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_l t1 RIGHT JOIN uprt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- full join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_l WHERE uprt1_l.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_l WHERE uprt2_l.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+
+-- lateral partition-wise join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+
+-- lateral references with clauses without equi-join on partition key
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1_l t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1_l t2 JOIN uprt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+			  ON t1.b = ss.t2a AND t1.c = ss.t2c WHERE t1.a % 25 = 0 ORDER BY t1.a;
-- 
1.7.9.5

