From 82e4452ff549ede9f34684d363f66291a3bb632b Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Tue, 7 Feb 2017 11:57:30 +0530
Subject: [PATCH 07/14] Partition-wise join tests.

This file does not contain tests for joins between multi-leveled partitioned
tables. Those will be added later.
---
 src/test/regress/expected/partition_join.out | 4114 ++++++++++++++++++++++++++
 src/test/regress/parallel_schedule           |    2 +-
 src/test/regress/serial_schedule             |    1 +
 src/test/regress/sql/partition_join.sql      |  515 ++++
 4 files changed, 4631 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/partition_join.out
 create mode 100644 src/test/regress/sql/partition_join.sql

diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
new file mode 100644
index 0000000..18238fa
--- /dev/null
+++ b/src/test/regress/expected/partition_join.out
@@ -0,0 +1,4114 @@
+--
+-- PARTITION_JOIN
+-- Test partition-wise join between partitioned tables
+--
+--
+-- partitioned by a single column
+--
+CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p1 PARTITION OF prt1 FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_p3 PARTITION OF prt1 FOR VALUES FROM (500) TO (600);
+CREATE TABLE prt1_p2 PARTITION OF prt1 FOR VALUES FROM (250) TO (500);
+INSERT INTO prt1 SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1;
+ANALYZE prt1_p1;
+ANALYZE prt1_p2;
+ANALYZE prt1_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1 AS SELECT * FROM prt1;
+CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p1 PARTITION OF prt2 FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_p2 PARTITION OF prt2 FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_p3 PARTITION OF prt2 FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2 SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+ANALYZE prt2;
+ANALYZE prt2_p1;
+ANALYZE prt2_p2;
+ANALYZE prt2_p3;
+CREATE TABLE uprt2 AS SELECT * FROM prt2;
+-- inner join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b 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)
+               ->  Seq Scan on public.prt2_p1 t2
+                     Output: t2.b, t2.c
+               ->  Hash
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_p1 t1
+                           Output: t1.a, t1.c
+                           Filter: ((t1.a % 25) = 0)
+         ->  Hash Join
+               Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+               Hash Cond: (t2_1.b = t1_2.a)
+               ->  Seq Scan on public.prt2_p2 t2_1
+                     Output: t2_1.b, t2_1.c
+               ->  Hash
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+         ->  Hash Join
+               Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+               Hash Cond: (t2_2.b = t1_1.a)
+               ->  Seq Scan on public.prt2_p3 t2_2
+                     Output: t2_2.b, t2_2.c
+               ->  Hash
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_p3 t1_1
+                           Output: t1_1.a, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+(34 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b 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 t1, uprt2 t2 WHERE t1.a = t2.b 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 outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b 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)
+               ->  Seq Scan on public.prt2_p1 t2
+                     Output: t2.b, t2.c
+               ->  Hash
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_p1 t1
+                           Output: t1.a, t1.c
+                           Filter: ((t1.a % 25) = 0)
+         ->  Hash Right Join
+               Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+               Hash Cond: (t2_1.b = t1_2.a)
+               ->  Seq Scan on public.prt2_p2 t2_1
+                     Output: t2_1.b, t2_1.c
+               ->  Hash
+                     Output: t1_2.a, t1_2.c
+                     ->  Seq Scan on public.prt1_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                           Filter: ((t1_2.a % 25) = 0)
+         ->  Hash Right Join
+               Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+               Hash Cond: (t2_2.b = t1_1.a)
+               ->  Seq Scan on public.prt2_p3 t2_2
+                     Output: t2_2.b, t2_2.c
+               ->  Hash
+                     Output: t1_1.a, t1_1.c
+                     ->  Seq Scan on public.prt1_p3 t1_1
+                           Output: t1_1.a, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+(34 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b 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 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b 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 outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b 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)
+                     ->  Seq Scan on public.prt1_p1 t1
+                           Output: t1.a, t1.c
+                     ->  Hash
+                           Output: t2.b, t2.c
+                           ->  Seq Scan on public.prt2_p1 t2
+                                 Output: t2.b, t2.c
+                                 Filter: ((t2.b % 25) = 0)
+               ->  Hash Right Join
+                     Output: t2_1.b, t2_1.c, t1_2.a, t1_2.c
+                     Hash Cond: (t1_2.a = t2_1.b)
+                     ->  Seq Scan on public.prt1_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                     ->  Hash
+                           Output: t2_1.b, t2_1.c
+                           ->  Seq Scan on public.prt2_p2 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_1.a, t1_1.c
+                     Hash Cond: (t1_1.a = t2_2.b)
+                     ->  Seq Scan on public.prt1_p3 t1_1
+                           Output: t1_1.a, t1_1.c
+                     ->  Hash
+                           Output: t2_2.b, t2_2.c
+                           ->  Seq Scan on public.prt2_p3 t2_2
+                                 Output: t2_2.b, t2_2.c
+                                 Filter: ((t2_2.b % 25) = 0)
+(36 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b 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 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b 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 outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c
+   Sort Key: prt1_p1.a, prt2_p1.b
+   ->  Append
+         ->  Hash Full Join
+               Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c
+               Hash Cond: (prt1_p1.a = prt2_p1.b)
+               ->  Seq Scan on public.prt1_p1
+                     Output: prt1_p1.a, prt1_p1.c
+                     Filter: ((prt1_p1.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p1.b, prt2_p1.c
+                     ->  Seq Scan on public.prt2_p1
+                           Output: prt2_p1.b, prt2_p1.c
+                           Filter: ((prt2_p1.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+               Hash Cond: (prt1_p2.a = prt2_p2.b)
+               ->  Seq Scan on public.prt1_p2
+                     Output: prt1_p2.a, prt1_p2.c
+                     Filter: ((prt1_p2.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p2.b, prt2_p2.c
+                     ->  Seq Scan on public.prt2_p2
+                           Output: prt2_p2.b, prt2_p2.c
+                           Filter: ((prt2_p2.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_p3.a, prt1_p3.c, prt2_p3.b, prt2_p3.c
+               Hash Cond: (prt1_p3.a = prt2_p3.b)
+               ->  Seq Scan on public.prt1_p3
+                     Output: prt1_p3.a, prt1_p3.c
+                     Filter: ((prt1_p3.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p3.b, prt2_p3.c
+                     ->  Seq Scan on public.prt2_p3
+                           Output: prt2_p3.b, prt2_p3.c
+                           Filter: ((prt2_p3.b % 25) = 0)
+(37 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) 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 t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b) 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)
+
+-- Cases with non-nullable expressions in subquery results;
+-- make sure these go to null as expected
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c
+   Sort Key: prt1_p1.a, prt2_p1.b
+   ->  Append
+         ->  Hash Full Join
+               Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c
+               Hash Cond: (prt1_p1.a = prt2_p1.b)
+               Filter: (((50) = prt1_p1.b) OR ((75) = prt2_p1.b))
+               ->  Seq Scan on public.prt1_p1
+                     Output: prt1_p1.a, prt1_p1.c, prt1_p1.b, 50
+                     Filter: ((prt1_p1.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p1.b, prt2_p1.c, (75)
+                     ->  Seq Scan on public.prt2_p1
+                           Output: prt2_p1.b, prt2_p1.c, 75
+                           Filter: ((prt2_p1.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+               Hash Cond: (prt1_p2.a = prt2_p2.b)
+               Filter: (((50) = prt1_p2.b) OR ((75) = prt2_p2.b))
+               ->  Seq Scan on public.prt1_p2
+                     Output: prt1_p2.a, prt1_p2.c, prt1_p2.b, 50
+                     Filter: ((prt1_p2.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p2.b, prt2_p2.c, (75)
+                     ->  Seq Scan on public.prt2_p2
+                           Output: prt2_p2.b, prt2_p2.c, 75
+                           Filter: ((prt2_p2.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_p3.a, prt1_p3.c, prt2_p3.b, prt2_p3.c
+               Hash Cond: (prt1_p3.a = prt2_p3.b)
+               Filter: (((50) = prt1_p3.b) OR ((75) = prt2_p3.b))
+               ->  Seq Scan on public.prt1_p3
+                     Output: prt1_p3.a, prt1_p3.c, prt1_p3.b, 50
+                     Filter: ((prt1_p3.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_p3.b, prt2_p3.c, (75)
+                     ->  Seq Scan on public.prt2_p3
+                           Output: prt2_p3.b, prt2_p3.c, 75
+                           Filter: ((prt2_p3.b % 25) = 0)
+(40 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+ a  |  c   | b  |  c   
+----+------+----+------
+ 50 | 0050 |    | 
+    |      | 75 | 0075
+(2 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+ a  |  c   | b  |  c   
+----+------+----+------
+ 50 | 0050 |    | 
+    |      | 75 | 0075
+(2 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, (25), prt2_p1.b, prt2_p1.c, (50)
+   Sort Key: prt1_p1.a, prt2_p1.b
+   ->  Result
+         Output: prt1_p1.a, prt1_p1.c, (25), prt2_p1.b, prt2_p1.c, (50)
+         ->  Append
+               ->  Hash Full Join
+                     Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c, (25), (50)
+                     Hash Cond: (prt1_p1.a = prt2_p1.b)
+                     ->  Seq Scan on public.prt1_p1
+                           Output: prt1_p1.a, prt1_p1.c, 25
+                           Filter: ((prt1_p1.a % 25) = 0)
+                     ->  Hash
+                           Output: prt2_p1.b, prt2_p1.c, (50)
+                           ->  Seq Scan on public.prt2_p1
+                                 Output: prt2_p1.b, prt2_p1.c, 50
+                                 Filter: ((prt2_p1.b % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c, (25), (50)
+                     Hash Cond: (prt1_p2.a = prt2_p2.b)
+                     ->  Seq Scan on public.prt1_p2
+                           Output: prt1_p2.a, prt1_p2.c, 25
+                           Filter: ((prt1_p2.a % 25) = 0)
+                     ->  Hash
+                           Output: prt2_p2.b, prt2_p2.c, (50)
+                           ->  Seq Scan on public.prt2_p2
+                                 Output: prt2_p2.b, prt2_p2.c, 50
+                                 Filter: ((prt2_p2.b % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p3.a, prt1_p3.c, prt2_p3.b, prt2_p3.c, (25), (50)
+                     Hash Cond: (prt1_p3.a = prt2_p3.b)
+                     ->  Seq Scan on public.prt1_p3
+                           Output: prt1_p3.a, prt1_p3.c, 25
+                           Filter: ((prt1_p3.a % 25) = 0)
+                     ->  Hash
+                           Output: prt2_p3.b, prt2_p3.c, (50)
+                           ->  Seq Scan on public.prt2_p3
+                                 Output: prt2_p3.b, prt2_p3.c, 50
+                                 Filter: ((prt2_p3.b % 25) = 0)
+(39 rows)
+
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+  a  |  c   | phv |  b  |  c   | phv 
+-----+------+-----+-----+------+-----
+   0 | 0000 |  25 |   0 | 0000 |  50
+  50 | 0050 |  25 |     |      |    
+ 100 | 0100 |  25 |     |      |    
+ 150 | 0150 |  25 | 150 | 0150 |  50
+ 200 | 0200 |  25 |     |      |    
+ 250 | 0250 |  25 |     |      |    
+ 300 | 0300 |  25 | 300 | 0300 |  50
+ 350 | 0350 |  25 |     |      |    
+ 400 | 0400 |  25 |     |      |    
+ 450 | 0450 |  25 | 450 | 0450 |  50
+ 500 | 0500 |  25 |     |      |    
+ 550 | 0550 |  25 |     |      |    
+     |      |     |  75 | 0075 |  50
+     |      |     | 225 | 0225 |  50
+     |      |     | 375 | 0375 |  50
+     |      |     | 525 | 0525 |  50
+(16 rows)
+
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+  a  |  c   | phv |  b  |  c   | phv 
+-----+------+-----+-----+------+-----
+   0 | 0000 |  25 |   0 | 0000 |  50
+  50 | 0050 |  25 |     |      |    
+ 100 | 0100 |  25 |     |      |    
+ 150 | 0150 |  25 | 150 | 0150 |  50
+ 200 | 0200 |  25 |     |      |    
+ 250 | 0250 |  25 |     |      |    
+ 300 | 0300 |  25 | 300 | 0300 |  50
+ 350 | 0350 |  25 |     |      |    
+ 400 | 0400 |  25 |     |      |    
+ 450 | 0450 |  25 | 450 | 0450 |  50
+ 500 | 0500 |  25 |     |      |    
+ 550 | 0550 |  25 |     |      |    
+     |      |     |  75 | 0075 |  50
+     |      |     | 225 | 0225 |  50
+     |      |     | 375 | 0375 |  50
+     |      |     | 525 | 0525 |  50
+(16 rows)
+
+-- Join with pruned partitions from joining relations
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 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)
+               ->  Seq Scan on public.prt2_p2 t2
+                     Output: t2.b, t2.c
+                     Filter: (t2.b > 250)
+               ->  Hash
+                     Output: t1.a, t1.c
+                     ->  Seq Scan on public.prt1_p2 t1
+                           Output: t1.a, t1.c
+                           Filter: ((t1.a < 450) AND ((t1.a % 25) = 0))
+(15 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+ 300 | 0300 | 300 | 0300
+(1 row)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1 t1, uprt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+ 300 | 0300 | 300 | 0300
+(1 row)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                    QUERY PLAN                                    
+----------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, b, c
+   Sort Key: prt1_p1.a, b
+   ->  Append
+         ->  Nested Loop Left Join
+               Output: prt1_p1.a, prt1_p1.c, b, c
+               Join Filter: (prt1_p1.a = b)
+               ->  Seq Scan on public.prt1_p1
+                     Output: prt1_p1.a, prt1_p1.c
+                     Filter: ((prt1_p1.a < 450) AND ((prt1_p1.a % 25) = 0))
+               ->  Result
+                     Output: b, c
+                     One-Time Filter: false
+         ->  Hash Right Join
+               Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+               Hash Cond: (prt2_p2.b = prt1_p2.a)
+               ->  Seq Scan on public.prt2_p2
+                     Output: prt2_p2.b, prt2_p2.c
+                     Filter: (prt2_p2.b > 250)
+               ->  Hash
+                     Output: prt1_p2.a, prt1_p2.c
+                     ->  Seq Scan on public.prt1_p2
+                           Output: prt1_p2.a, prt1_p2.c
+                           Filter: ((prt1_p2.a < 450) AND ((prt1_p2.a % 25) = 0))
+(24 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |     | 
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 |     | 
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+(9 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM uprt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |     | 
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 |     | 
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+(9 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+   Sort Key: prt1_p2.a, prt2_p2.b
+   ->  Result
+         Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: prt2_p2.b, prt2_p2.c, prt1_p2.a, prt1_p2.c
+                     Hash Cond: (prt1_p2.a = prt2_p2.b)
+                     ->  Seq Scan on public.prt1_p2
+                           Output: prt1_p2.a, prt1_p2.c
+                           Filter: (prt1_p2.a < 450)
+                     ->  Hash
+                           Output: prt2_p2.b, prt2_p2.c
+                           ->  Seq Scan on public.prt2_p2
+                                 Output: prt2_p2.b, prt2_p2.c
+                                 Filter: ((prt2_p2.b > 250) AND ((prt2_p2.a % 25) = 0))
+               ->  Nested Loop Left Join
+                     Output: prt2_p3.b, prt2_p3.c, a, c
+                     Join Filter: (a = prt2_p3.b)
+                     ->  Seq Scan on public.prt2_p3
+                           Output: prt2_p3.b, prt2_p3.c
+                           Filter: ((prt2_p3.b > 250) AND ((prt2_p3.a % 25) = 0))
+                     ->  Result
+                           Output: a, c
+                           One-Time Filter: false
+(26 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+ 300 | 0300 | 300 | 0300
+     |      | 375 | 0375
+     |      | 450 | 0450
+     |      | 525 | 0525
+(4 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM uprt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+ 300 | 0300 | 300 | 0300
+     |      | 375 | 0375
+     |      | 450 | 0450
+     |      | 525 | 0525
+(4 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+                                    QUERY PLAN                                    
+----------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, b, c
+   Sort Key: prt1_p1.a, b
+   ->  Append
+         ->  Hash Full Join
+               Output: prt1_p1.a, prt1_p1.c, b, c
+               Hash Cond: (prt1_p1.a = b)
+               ->  Seq Scan on public.prt1_p1
+                     Output: prt1_p1.a, prt1_p1.c
+                     Filter: ((prt1_p1.a < 450) AND ((prt1_p1.a % 25) = 0))
+               ->  Hash
+                     Output: b, c
+                     ->  Result
+                           Output: b, c
+                           One-Time Filter: false
+         ->  Hash Full Join
+               Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+               Hash Cond: (prt1_p2.a = prt2_p2.b)
+               ->  Seq Scan on public.prt1_p2
+                     Output: prt1_p2.a, prt1_p2.c
+                     Filter: ((prt1_p2.a < 450) AND ((prt1_p2.a % 25) = 0))
+               ->  Hash
+                     Output: prt2_p2.b, prt2_p2.c
+                     ->  Seq Scan on public.prt2_p2
+                           Output: prt2_p2.b, prt2_p2.c
+                           Filter: ((prt2_p2.b > 250) AND ((prt2_p2.b % 25) = 0))
+         ->  Hash Full Join
+               Output: a, c, prt2_p3.b, prt2_p3.c
+               Hash Cond: (prt2_p3.b = a)
+               ->  Seq Scan on public.prt2_p3
+                     Output: prt2_p3.b, prt2_p3.c
+                     Filter: ((prt2_p3.b > 250) AND ((prt2_p3.b % 25) = 0))
+               ->  Hash
+                     Output: a, c
+                     ->  Result
+                           Output: a, c
+                           One-Time Filter: false
+(37 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |     | 
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 |     | 
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+     |      | 375 | 0375
+     |      | 450 | 0450
+     |      | 525 | 0525
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   
+-----+------+-----+------
+   0 | 0000 |     | 
+  50 | 0050 |     | 
+ 100 | 0100 |     | 
+ 150 | 0150 |     | 
+ 200 | 0200 |     | 
+ 250 | 0250 |     | 
+ 300 | 0300 | 300 | 0300
+ 350 | 0350 |     | 
+ 400 | 0400 |     | 
+     |      | 375 | 0375
+     |      | 450 | 0450
+     |      | 525 | 0525
+(12 rows)
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+                     QUERY PLAN                     
+----------------------------------------------------
+ Merge Append
+   Sort Key: t1.a
+   ->  Merge Semi Join
+         Output: t1.a, t1.b, t1.c
+         Merge Cond: (t1.a = t1_3.b)
+         ->  Sort
+               Output: t1.a, t1.b, t1.c
+               Sort Key: t1.a
+               ->  Seq Scan on public.prt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+         ->  Sort
+               Output: t1_3.b
+               Sort Key: t1_3.b
+               ->  Seq Scan on public.prt2_p1 t1_3
+                     Output: t1_3.b
+                     Filter: ((t1_3.b % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_2.a, t1_2.b, t1_2.c
+         Merge Cond: (t1_2.a = t1_4.b)
+         ->  Sort
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Sort Key: t1_2.a
+               ->  Seq Scan on public.prt1_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+         ->  Sort
+               Output: t1_4.b
+               Sort Key: t1_4.b
+               ->  Seq Scan on public.prt2_p2 t1_4
+                     Output: t1_4.b
+                     Filter: ((t1_4.b % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_1.a, t1_1.b, t1_1.c
+         Merge Cond: (t1_1.a = t1_5.b)
+         ->  Sort
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Sort Key: t1_1.a
+               ->  Seq Scan on public.prt1_p3 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+         ->  Sort
+               Output: t1_5.b
+               Sort Key: t1_5.b
+               ->  Seq Scan on public.prt2_p3 t1_5
+                     Output: t1_5.b
+                     Filter: ((t1_5.b % 25) = 0)
+(47 rows)
+
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+-- lateral reference
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                             QUERY PLAN                                              
+-----------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, 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, 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, t3.a, (LEAST(t1.a, t2.a, t3.a))
+                     ->  Seq Scan on public.prt1_p1 t1
+                           Output: t1.a, t1.b, t1.c
+                           Filter: ((t1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2.a, t3.a, LEAST(t1.a, t2.a, t3.a)
+                           Hash Cond: (t3.b = t2.a)
+                           ->  Seq Scan on public.prt2_p1 t3
+                                 Output: t3.a, t3.b
+                           ->  Hash
+                                 Output: t2.a
+                                 ->  Seq Scan on public.prt1_p1 t2
+                                       Output: t2.a
+                                       Filter: (t1.a = t2.a)
+               ->  Nested Loop Left Join
+                     Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t3_1.a, (LEAST(t1_2.a, t2_2.a, t3_1.a))
+                     ->  Seq Scan on public.prt1_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, t3_1.a, LEAST(t1_2.a, t2_2.a, t3_1.a)
+                           Hash Cond: (t3_1.b = t2_2.a)
+                           ->  Seq Scan on public.prt2_p2 t3_1
+                                 Output: t3_1.a, t3_1.b
+                           ->  Hash
+                                 Output: t2_2.a
+                                 ->  Seq Scan on public.prt1_p2 t2_2
+                                       Output: t2_2.a
+                                       Filter: (t1_2.a = t2_2.a)
+               ->  Nested Loop Left Join
+                     Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t3_2.a, (LEAST(t1_1.a, t2_1.a, t3_2.a))
+                     ->  Seq Scan on public.prt1_p3 t1_1
+                           Output: t1_1.a, t1_1.b, t1_1.c
+                           Filter: ((t1_1.a % 25) = 0)
+                     ->  Hash Join
+                           Output: t2_1.a, t3_2.a, LEAST(t1_1.a, t2_1.a, t3_2.a)
+                           Hash Cond: (t3_2.b = t2_1.a)
+                           ->  Seq Scan on public.prt2_p3 t3_2
+                                 Output: t3_2.a, t3_2.b
+                           ->  Hash
+                                 Output: t2_1.a
+                                 ->  Seq Scan on public.prt1_p3 t2_1
+                                       Output: t2_1.a
+                                       Filter: (t1_1.a = t2_1.a)
+(51 rows)
+
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c, t2.a, 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, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+         ->  Append
+               ->  Seq Scan on public.prt1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_p1 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Seq Scan on public.prt1_p3 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Seq Scan on public.prt1_p2 t1_3
+                     Output: t1_3.a, t1_3.b, t1_3.c
+                     Filter: ((t1_3.a % 25) = 0)
+         ->  Append
+               ->  Hash Join
+                     Output: t2.a, t3.a, LEAST(t1.a, t2.a, t3.a)
+                     Hash Cond: (t3.b = t2.a)
+                     ->  Seq Scan on public.prt2_p1 t3
+                           Output: t3.a, t3.b
+                     ->  Hash
+                           Output: t2.a
+                           ->  Seq Scan on public.prt1_p1 t2
+                                 Output: t2.a
+                                 Filter: (t1.b = t2.a)
+               ->  Hash Join
+                     Output: t2_2.a, t3_1.a, LEAST(t1.a, t2_2.a, t3_1.a)
+                     Hash Cond: (t3_1.b = t2_2.a)
+                     ->  Seq Scan on public.prt2_p2 t3_1
+                           Output: t3_1.a, t3_1.b
+                     ->  Hash
+                           Output: t2_2.a
+                           ->  Seq Scan on public.prt1_p2 t2_2
+                                 Output: t2_2.a
+                                 Filter: (t1.b = t2_2.a)
+               ->  Hash Join
+                     Output: t2_1.a, t3_2.a, LEAST(t1.a, t2_1.a, t3_2.a)
+                     Hash Cond: (t3_2.b = t2_1.a)
+                     ->  Seq Scan on public.prt2_p3 t3_2
+                           Output: t3_2.a, t3_2.b
+                     ->  Hash
+                           Output: t2_1.a
+                           ->  Seq Scan on public.prt1_p3 t2_1
+                                 Output: t2_1.a
+                                 Filter: (t1.b = t2_1.a)
+(49 rows)
+
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+--
+-- partitioned by expression
+--
+CREATE TABLE prt1_e (a int, b int, c varchar) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p1 PARTITION OF prt1_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_e_p2 PARTITION OF prt1_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt1_e_p3 PARTITION OF prt1_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt1_e SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_e;
+ANALYZE prt1_e_p1;
+ANALYZE prt1_e_p2;
+ANALYZE prt1_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_e AS SELECT * FROM prt1_e;
+CREATE TABLE prt2_e (a int, b int, c varchar) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p1 PARTITION OF prt2_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_e_p2 PARTITION OF prt2_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_e_p3 PARTITION OF prt2_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2_e SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_e;
+ANALYZE prt2_e_p1;
+ANALYZE prt2_e_p2;
+ANALYZE prt2_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_e AS SELECT * FROM prt2_e;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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, t2.b
+   ->  Append
+         ->  Hash Join
+               Output: t1.a, t1.c, t2.b, t2.c
+               Hash Cond: (((t2.b + t2.a) / 2) = ((t1.a + t1.b) / 2))
+               ->  Seq Scan on public.prt2_e_p1 t2
+                     Output: t2.b, t2.c, t2.a
+               ->  Hash
+                     Output: t1.a, t1.c, t1.b
+                     ->  Seq Scan on public.prt1_e_p1 t1
+                           Output: t1.a, t1.c, t1.b
+                           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 + t2_1.a) / 2) = ((t1_1.a + t1_1.b) / 2))
+               ->  Seq Scan on public.prt2_e_p2 t2_1
+                     Output: t2_1.b, t2_1.c, t2_1.a
+               ->  Hash
+                     Output: t1_1.a, t1_1.c, t1_1.b
+                     ->  Seq Scan on public.prt1_e_p2 t1_1
+                           Output: t1_1.a, t1_1.c, t1_1.b
+                           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 + t2_2.a) / 2) = ((t1_2.a + t1_2.b) / 2))
+               ->  Seq Scan on public.prt2_e_p3 t2_2
+                     Output: t2_2.b, t2_2.c, t2_2.a
+               ->  Hash
+                     Output: t1_2.a, t1_2.c, t1_2.b
+                     ->  Seq Scan on public.prt1_e_p3 t1_2
+                           Output: t1_2.a, t1_2.c, t1_2.b
+                           Filter: ((t1_2.a % 25) = 0)
+(34 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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_e t1, uprt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1 LEFT JOIN prt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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 + t2.a) / 2) = ((t1.a + t1.b) / 2))
+               ->  Seq Scan on public.prt2_e_p1 t2
+                     Output: t2.b, t2.c, t2.a
+               ->  Hash
+                     Output: t1.a, t1.c, t1.b
+                     ->  Seq Scan on public.prt1_e_p1 t1
+                           Output: t1.a, t1.c, t1.b
+                           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 + t2_1.a) / 2) = ((t1_1.a + t1_1.b) / 2))
+               ->  Seq Scan on public.prt2_e_p2 t2_1
+                     Output: t2_1.b, t2_1.c, t2_1.a
+               ->  Hash
+                     Output: t1_1.a, t1_1.c, t1_1.b
+                     ->  Seq Scan on public.prt1_e_p2 t1_1
+                           Output: t1_1.a, t1_1.c, t1_1.b
+                           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 + t2_2.a) / 2) = ((t1_2.a + t1_2.b) / 2))
+               ->  Seq Scan on public.prt2_e_p3 t2_2
+                     Output: t2_2.b, t2_2.c, t2_2.a
+               ->  Hash
+                     Output: t1_2.a, t1_2.c, t1_2.b
+                     ->  Seq Scan on public.prt1_e_p3 t1_2
+                           Output: t1_2.a, t1_2.c, t1_2.b
+                           Filter: ((t1_2.a % 25) = 0)
+(34 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1 LEFT JOIN prt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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_e t1 LEFT JOIN uprt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 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)
+
+--
+-- N-way join
+--
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Join
+                     Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                     Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
+                     ->  Seq Scan on public.prt1_e_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t1.a, t1.c, t2.b, t2.c
+                           ->  Hash Join
+                                 Output: t1.a, t1.c, t2.b, t2.c
+                                 Hash Cond: (t2.b = t1.a)
+                                 ->  Seq Scan on public.prt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t1.a, t1.c
+                                       ->  Seq Scan on public.prt1_p1 t1
+                                             Output: t1.a, t1.c
+                                             Filter: ((t1.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                     Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_2.a)
+                     ->  Seq Scan on public.prt1_e_p2 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                           ->  Hash Join
+                                 Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                                 Hash Cond: (t2_1.b = t1_2.a)
+                                 ->  Seq Scan on public.prt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t1_2.a, t1_2.c
+                                       ->  Seq Scan on public.prt1_p2 t1_2
+                                             Output: t1_2.a, t1_2.c
+                                             Filter: ((t1_2.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                     Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_1.a)
+                     ->  Seq Scan on public.prt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                           ->  Hash Join
+                                 Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                                 Hash Cond: (t2_2.b = t1_1.a)
+                                 ->  Seq Scan on public.prt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t1_1.a, t1_1.c
+                                       ->  Seq Scan on public.prt1_p3 t1_1
+                                             Output: t1_1.a, t1_1.c
+                                             Filter: ((t1_1.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+(4 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM uprt1 t1, uprt2 t2, uprt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+(4 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                     Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
+                     ->  Seq Scan on public.prt1_e_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t1.a, t1.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t1.a, t1.c, t2.b, t2.c
+                                 Hash Cond: (t2.b = t1.a)
+                                 ->  Seq Scan on public.prt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t1.a, t1.c
+                                       ->  Seq Scan on public.prt1_p1 t1
+                                             Output: t1.a, t1.c
+                                             Filter: ((t1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                     Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_2.a)
+                     ->  Seq Scan on public.prt1_e_p2 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                           ->  Hash Right Join
+                                 Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                                 Hash Cond: (t2_1.b = t1_2.a)
+                                 ->  Seq Scan on public.prt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t1_2.a, t1_2.c
+                                       ->  Seq Scan on public.prt1_p2 t1_2
+                                             Output: t1_2.a, t1_2.c
+                                             Filter: ((t1_2.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                     Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_1.a)
+                     ->  Seq Scan on public.prt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                           ->  Hash Right Join
+                                 Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                                 Hash Cond: (t2_2.b = t1_1.a)
+                                 ->  Seq Scan on public.prt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t1_1.a, t1_1.c
+                                       ->  Seq Scan on public.prt1_p3 t1_1
+                                             Output: t1_1.a, t1_1.c
+                                             Filter: ((t1_1.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) LEFT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                     Hash Cond: (((t3.a + t3.b) / 2) = t2.b)
+                     ->  Seq Scan on public.prt1_e_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t1.a, t1.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t1.a, t1.c, t2.b, t2.c
+                                 Hash Cond: (t2.b = t1.a)
+                                 ->  Seq Scan on public.prt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t1.a, t1.c
+                                       ->  Seq Scan on public.prt1_p1 t1
+                                             Output: t1.a, t1.c
+                                             Filter: ((t1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                     Hash Cond: (((t3_1.a + t3_1.b) / 2) = t2_1.b)
+                     ->  Seq Scan on public.prt1_e_p2 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                           ->  Hash Right Join
+                                 Output: t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                                 Hash Cond: (t2_1.b = t1_2.a)
+                                 ->  Seq Scan on public.prt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t1_2.a, t1_2.c
+                                       ->  Seq Scan on public.prt1_p2 t1_2
+                                             Output: t1_2.a, t1_2.c
+                                             Filter: ((t1_2.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                     Hash Cond: (((t3_2.a + t3_2.b) / 2) = t2_2.b)
+                     ->  Seq Scan on public.prt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                           ->  Hash Right Join
+                                 Output: t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                                 Hash Cond: (t2_2.b = t1_1.a)
+                                 ->  Seq Scan on public.prt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t1_1.a, t1_1.c
+                                       ->  Seq Scan on public.prt1_p3 t1_1
+                                             Output: t1_1.a, t1_1.c
+                                             Filter: ((t1_1.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |          | 
+ 100 | 0100 |     |      |          | 
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |          | 
+ 250 | 0250 |     |      |          | 
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |          | 
+ 400 | 0400 |     |      |          | 
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |          | 
+ 550 | 0550 |     |      |          | 
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) LEFT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |          | 
+ 100 | 0100 |     |      |          | 
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |          | 
+ 250 | 0250 |     |      |          | 
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |          | 
+ 400 | 0400 |     |      |          | 
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |          | 
+ 550 | 0550 |     |      |          | 
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t3.a, t3.b, t3.c, t1.a, t1.c, t2.b, t2.c
+                     Hash Cond: (t2.b = t1.a)
+                     ->  Seq Scan on public.prt2_p1 t2
+                           Output: t2.b, t2.c
+                     ->  Hash
+                           Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                           ->  Hash Right Join
+                                 Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                                 Hash Cond: (t1.a = ((t3.a + t3.b) / 2))
+                                 ->  Seq Scan on public.prt1_p1 t1
+                                       Output: t1.a, t1.c
+                                 ->  Hash
+                                       Output: t3.a, t3.b, t3.c
+                                       ->  Seq Scan on public.prt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c
+                                             Filter: ((t3.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                     Hash Cond: (t2_1.b = t1_2.a)
+                     ->  Seq Scan on public.prt2_p2 t2_1
+                           Output: t2_1.b, t2_1.c
+                     ->  Hash
+                           Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                           ->  Hash Right Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                                 Hash Cond: (t1_2.a = ((t3_1.a + t3_1.b) / 2))
+                                 ->  Seq Scan on public.prt1_p2 t1_2
+                                       Output: t1_2.a, t1_2.c
+                                 ->  Hash
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       ->  Seq Scan on public.prt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c
+                                             Filter: ((t3_1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                     Hash Cond: (t2_2.b = t1_1.a)
+                     ->  Seq Scan on public.prt2_p3 t2_2
+                           Output: t2_2.b, t2_2.c
+                     ->  Hash
+                           Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                           ->  Hash Right Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                                 Hash Cond: (t1_1.a = ((t3_2.a + t3_2.b) / 2))
+                                 ->  Seq Scan on public.prt1_p3 t1_1
+                                       Output: t1_1.a, t1_1.c
+                                 ->  Hash
+                                       Output: t3_2.a, t3_2.b, t3_2.c
+                                       ->  Seq Scan on public.prt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c
+                                             Filter: ((t3_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t3.a, t3.b, t3.c, t2.b, t2.c, t1.a, t1.c
+                     Hash Cond: (t1.a = t2.b)
+                     ->  Seq Scan on public.prt1_p1 t1
+                           Output: t1.a, t1.c
+                     ->  Hash
+                           Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                                 Hash Cond: (t2.b = ((t3.a + t3.b) / 2))
+                                 ->  Seq Scan on public.prt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t3.a, t3.b, t3.c
+                                       ->  Seq Scan on public.prt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c
+                                             Filter: ((t3.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c, t1_2.a, t1_2.c
+                     Hash Cond: (t1_2.a = t2_1.b)
+                     ->  Seq Scan on public.prt1_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+                     ->  Hash
+                           Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                           ->  Hash Right Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                                 Hash Cond: (t2_1.b = ((t3_1.a + t3_1.b) / 2))
+                                 ->  Seq Scan on public.prt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       ->  Seq Scan on public.prt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c
+                                             Filter: ((t3_1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c, t1_1.a, t1_1.c
+                     Hash Cond: (t1_1.a = t2_2.b)
+                     ->  Seq Scan on public.prt1_p3 t1_1
+                           Output: t1_1.a, t1_1.c
+                     ->  Hash
+                           Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                           ->  Hash Right Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                                 Hash Cond: (t2_2.b = ((t3_2.a + t3_2.b) / 2))
+                                 ->  Seq Scan on public.prt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t3_2.a, t3_2.b, t3_2.c
+                                       ->  Seq Scan on public.prt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c
+                                             Filter: ((t3_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                                  QUERY PLAN                                                   
+---------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c, ((prt1_e_p1.a + prt1_e_p1.b)), prt1_e_p1.c
+   Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b))
+   ->  Result
+         Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c, (prt1_e_p1.a + prt1_e_p1.b), prt1_e_p1.c
+         ->  Append
+               ->  Hash Full Join
+                     Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c, prt1_e_p1.a, prt1_e_p1.b, prt1_e_p1.c
+                     Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2))
+                     ->  Hash Full Join
+                           Output: prt1_p1.a, prt1_p1.c, prt2_p1.b, prt2_p1.c
+                           Hash Cond: (prt1_p1.a = prt2_p1.b)
+                           ->  Seq Scan on public.prt1_p1
+                                 Output: prt1_p1.a, prt1_p1.c
+                                 Filter: ((prt1_p1.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p1.b, prt2_p1.c
+                                 ->  Seq Scan on public.prt2_p1
+                                       Output: prt2_p1.b, prt2_p1.c
+                                       Filter: ((prt2_p1.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p1.a, prt1_e_p1.b, prt1_e_p1.c
+                           ->  Seq Scan on public.prt1_e_p1
+                                 Output: prt1_e_p1.a, prt1_e_p1.b, prt1_e_p1.c
+                                 Filter: ((prt1_e_p1.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c, prt1_e_p2.a, prt1_e_p2.b, prt1_e_p2.c
+                     Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2))
+                     ->  Hash Full Join
+                           Output: prt1_p2.a, prt1_p2.c, prt2_p2.b, prt2_p2.c
+                           Hash Cond: (prt1_p2.a = prt2_p2.b)
+                           ->  Seq Scan on public.prt1_p2
+                                 Output: prt1_p2.a, prt1_p2.c
+                                 Filter: ((prt1_p2.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p2.b, prt2_p2.c
+                                 ->  Seq Scan on public.prt2_p2
+                                       Output: prt2_p2.b, prt2_p2.c
+                                       Filter: ((prt2_p2.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p2.a, prt1_e_p2.b, prt1_e_p2.c
+                           ->  Seq Scan on public.prt1_e_p2
+                                 Output: prt1_e_p2.a, prt1_e_p2.b, prt1_e_p2.c
+                                 Filter: ((prt1_e_p2.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p3.a, prt1_p3.c, prt2_p3.b, prt2_p3.c, prt1_e_p3.a, prt1_e_p3.b, prt1_e_p3.c
+                     Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2))
+                     ->  Hash Full Join
+                           Output: prt1_p3.a, prt1_p3.c, prt2_p3.b, prt2_p3.c
+                           Hash Cond: (prt1_p3.a = prt2_p3.b)
+                           ->  Seq Scan on public.prt1_p3
+                                 Output: prt1_p3.a, prt1_p3.c
+                                 Filter: ((prt1_p3.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p3.b, prt2_p3.c
+                                 ->  Seq Scan on public.prt2_p3
+                                       Output: prt2_p3.b, prt2_p3.c
+                                       Filter: ((prt2_p3.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p3.a, prt1_e_p3.b, prt1_e_p3.c
+                           ->  Seq Scan on public.prt1_e_p3
+                                 Output: prt1_e_p3.a, prt1_e_p3.b, prt1_e_p3.c
+                                 Filter: ((prt1_e_p3.a % 25) = 0)
+(63 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+     |      |  75 | 0075 |          | 
+     |      | 225 | 0225 |          | 
+     |      | 375 | 0375 |          | 
+     |      | 525 | 0525 |          | 
+(16 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM uprt1_e WHERE uprt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+     |      |  75 | 0075 |          | 
+     |      | 225 | 0225 |          | 
+     |      | 375 | 0375 |          | 
+     |      | 525 | 0525 |          | 
+(16 rows)
+
+-- Cases with non-nullable expressions in subquery results;
+-- make sure these go to null as expected
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                                      QUERY PLAN                                                      
+----------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_p1.a, (50), prt2_p1.b, (75), ((prt1_e_p1.a + prt1_e_p1.b)), (50)
+   Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b))
+   ->  Result
+         Output: prt1_p1.a, (50), prt2_p1.b, (75), (prt1_e_p1.a + prt1_e_p1.b), (50)
+         ->  Append
+               ->  Hash Full Join
+                     Output: prt1_p1.a, prt2_p1.b, prt1_e_p1.a, prt1_e_p1.b, (50), (75), (50)
+                     Hash Cond: (prt1_p1.a = ((prt1_e_p1.a + prt1_e_p1.b) / 2))
+                     Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50)))
+                     ->  Hash Full Join
+                           Output: prt1_p1.a, prt2_p1.b, (50), (75)
+                           Hash Cond: (prt1_p1.a = prt2_p1.b)
+                           ->  Seq Scan on public.prt1_p1
+                                 Output: prt1_p1.a, 50
+                                 Filter: ((prt1_p1.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p1.b, (75)
+                                 ->  Seq Scan on public.prt2_p1
+                                       Output: prt2_p1.b, 75
+                                       Filter: ((prt2_p1.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p1.a, prt1_e_p1.b, (50)
+                           ->  Seq Scan on public.prt1_e_p1
+                                 Output: prt1_e_p1.a, prt1_e_p1.b, 50
+                                 Filter: ((prt1_e_p1.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p2.a, prt2_p2.b, prt1_e_p2.a, prt1_e_p2.b, (50), (75), (50)
+                     Hash Cond: (prt1_p2.a = ((prt1_e_p2.a + prt1_e_p2.b) / 2))
+                     Filter: ((prt1_p2.a = (50)) OR (prt2_p2.b = (75)) OR (((prt1_e_p2.a + prt1_e_p2.b) / 2) = (50)))
+                     ->  Hash Full Join
+                           Output: prt1_p2.a, prt2_p2.b, (50), (75)
+                           Hash Cond: (prt1_p2.a = prt2_p2.b)
+                           ->  Seq Scan on public.prt1_p2
+                                 Output: prt1_p2.a, 50
+                                 Filter: ((prt1_p2.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p2.b, (75)
+                                 ->  Seq Scan on public.prt2_p2
+                                       Output: prt2_p2.b, 75
+                                       Filter: ((prt2_p2.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p2.a, prt1_e_p2.b, (50)
+                           ->  Seq Scan on public.prt1_e_p2
+                                 Output: prt1_e_p2.a, prt1_e_p2.b, 50
+                                 Filter: ((prt1_e_p2.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: prt1_p3.a, prt2_p3.b, prt1_e_p3.a, prt1_e_p3.b, (50), (75), (50)
+                     Hash Cond: (prt1_p3.a = ((prt1_e_p3.a + prt1_e_p3.b) / 2))
+                     Filter: ((prt1_p3.a = (50)) OR (prt2_p3.b = (75)) OR (((prt1_e_p3.a + prt1_e_p3.b) / 2) = (50)))
+                     ->  Hash Full Join
+                           Output: prt1_p3.a, prt2_p3.b, (50), (75)
+                           Hash Cond: (prt1_p3.a = prt2_p3.b)
+                           ->  Seq Scan on public.prt1_p3
+                                 Output: prt1_p3.a, 50
+                                 Filter: ((prt1_p3.a % 25) = 0)
+                           ->  Hash
+                                 Output: prt2_p3.b, (75)
+                                 ->  Seq Scan on public.prt2_p3
+                                       Output: prt2_p3.b, 75
+                                       Filter: ((prt2_p3.b % 25) = 0)
+                     ->  Hash
+                           Output: prt1_e_p3.a, prt1_e_p3.b, (50)
+                           ->  Seq Scan on public.prt1_e_p3
+                                 Output: prt1_e_p3.a, prt1_e_p3.b, 50
+                                 Filter: ((prt1_e_p3.a % 25) = 0)
+(66 rows)
+
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+ a  | phv | b  | phv | ?column? | phv 
+----+-----+----+-----+----------+-----
+ 50 |  50 |    |     |      100 |  50
+    |     | 75 |  75 |          |    
+(2 rows)
+
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM uprt1_e WHERE uprt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+ a  | phv | b  | phv | ?column? | phv 
+----+-----+----+-----+----------+-----
+ 50 |  50 |    |     |      100 |  50
+    |     | 75 |  75 |          |    
+(2 rows)
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+                            QUERY PLAN                             
+-------------------------------------------------------------------
+ Merge Append
+   Sort Key: t1.a
+   ->  Merge Semi Join
+         Output: t1.a, t1.b, t1.c
+         Merge Cond: (t1.a = t1_3.b)
+         ->  Sort
+               Output: t1.a, t1.b, t1.c
+               Sort Key: t1.a
+               ->  Seq Scan on public.prt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+         ->  Sort
+               Output: t1_3.b, t2.a, t2.b
+               Sort Key: t1_3.b
+               ->  Hash Join
+                     Output: t1_3.b, t2.a, t2.b
+                     Hash Cond: (((t2.a + t2.b) / 2) = t1_3.b)
+                     ->  Seq Scan on public.prt1_e_p1 t2
+                           Output: t2.a, t2.b
+                     ->  Hash
+                           Output: t1_3.b
+                           ->  Seq Scan on public.prt2_p1 t1_3
+                                 Output: t1_3.b
+                                 Filter: ((t1_3.b % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_2.a, t1_2.b, t1_2.c
+         Merge Cond: (t1_2.a = t1_4.b)
+         ->  Sort
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Sort Key: t1_2.a
+               ->  Seq Scan on public.prt1_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+         ->  Sort
+               Output: t1_4.b, t2_1.a, t2_1.b
+               Sort Key: t1_4.b
+               ->  Hash Join
+                     Output: t1_4.b, t2_1.a, t2_1.b
+                     Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_4.b)
+                     ->  Seq Scan on public.prt1_e_p2 t2_1
+                           Output: t2_1.a, t2_1.b
+                     ->  Hash
+                           Output: t1_4.b
+                           ->  Seq Scan on public.prt2_p2 t1_4
+                                 Output: t1_4.b
+                                 Filter: ((t1_4.b % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_1.a, t1_1.b, t1_1.c
+         Merge Cond: (t1_1.a = t1_5.b)
+         ->  Sort
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Sort Key: t1_1.a
+               ->  Seq Scan on public.prt1_p3 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+         ->  Sort
+               Output: t1_5.b, t2_2.a, t2_2.b
+               Sort Key: t1_5.b
+               ->  Hash Join
+                     Output: t1_5.b, t2_2.a, t2_2.b
+                     Hash Cond: (((t2_2.a + t2_2.b) / 2) = t1_5.b)
+                     ->  Seq Scan on public.prt1_e_p3 t2_2
+                           Output: t2_2.a, t2_2.b
+                     ->  Hash
+                           Output: t1_5.b
+                           ->  Seq Scan on public.prt2_p3 t1_5
+                                 Output: t1_5.b
+                                 Filter: ((t1_5.b % 25) = 0)
+(68 rows)
+
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1, uprt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+                            QUERY PLAN                             
+-------------------------------------------------------------------
+ Merge Append
+   Sort Key: t1.a
+   ->  Merge Semi Join
+         Output: t1.a, t1.b, t1.c
+         Merge Cond: (t1.a = t1_3.b)
+         ->  Sort
+               Output: t1.a, t1.b, t1.c
+               Sort Key: t1.a
+               ->  Seq Scan on public.prt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+         ->  Sort
+               Output: t1_3.b, t1_6.a, t1_6.b
+               Sort Key: t1_3.b
+               ->  Hash Semi Join
+                     Output: t1_3.b, t1_6.a, t1_6.b
+                     Hash Cond: (t1_3.b = ((t1_6.a + t1_6.b) / 2))
+                     ->  Seq Scan on public.prt2_p1 t1_3
+                           Output: t1_3.b
+                     ->  Hash
+                           Output: t1_6.a, t1_6.b
+                           ->  Seq Scan on public.prt1_e_p1 t1_6
+                                 Output: t1_6.a, t1_6.b
+                                 Filter: ((t1_6.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_2.a, t1_2.b, t1_2.c
+         Merge Cond: (t1_2.a = t1_4.b)
+         ->  Sort
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Sort Key: t1_2.a
+               ->  Seq Scan on public.prt1_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+         ->  Sort
+               Output: t1_4.b, t1_7.a, t1_7.b
+               Sort Key: t1_4.b
+               ->  Hash Semi Join
+                     Output: t1_4.b, t1_7.a, t1_7.b
+                     Hash Cond: (t1_4.b = ((t1_7.a + t1_7.b) / 2))
+                     ->  Seq Scan on public.prt2_p2 t1_4
+                           Output: t1_4.b
+                     ->  Hash
+                           Output: t1_7.a, t1_7.b
+                           ->  Seq Scan on public.prt1_e_p2 t1_7
+                                 Output: t1_7.a, t1_7.b
+                                 Filter: ((t1_7.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_1.a, t1_1.b, t1_1.c
+         Merge Cond: (t1_1.a = t1_5.b)
+         ->  Sort
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Sort Key: t1_1.a
+               ->  Seq Scan on public.prt1_p3 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+         ->  Sort
+               Output: t1_5.b, t1_8.a, t1_8.b
+               Sort Key: t1_5.b
+               ->  Hash Semi Join
+                     Output: t1_5.b, t1_8.a, t1_8.b
+                     Hash Cond: (t1_5.b = ((t1_8.a + t1_8.b) / 2))
+                     ->  Seq Scan on public.prt2_p3 t1_5
+                           Output: t1_5.b
+                     ->  Hash
+                           Output: t1_8.a, t1_8.b
+                           ->  Seq Scan on public.prt1_e_p3 t1_8
+                                 Output: t1_8.a, t1_8.b
+                                 Filter: ((t1_8.a % 25) = 0)
+(68 rows)
+
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+-- test merge joins with and without using indexes
+SET enable_hashjoin TO off;
+SET enable_nestloop TO off;
+CREATE INDEX iprt1_p1_a on prt1_p1(a);
+CREATE INDEX iprt1_p2_a on prt1_p2(a);
+CREATE INDEX iprt1_p3_a on prt1_p3(a);
+CREATE INDEX iprt2_p1_b on prt2_p1(b);
+CREATE INDEX iprt2_p2_b on prt2_p2(b);
+CREATE INDEX iprt2_p3_b on prt2_p3(b);
+CREATE INDEX iprt1_e_p1_ab2 on prt1_e_p1(((a+b)/2));
+CREATE INDEX iprt1_e_p2_ab2 on prt1_e_p2(((a+b)/2));
+CREATE INDEX iprt1_e_p3_ab2 on prt1_e_p3(((a+b)/2));
+ANALYZE prt1;
+ANALYZE prt1_p1;
+ANALYZE prt1_p2;
+ANALYZE prt1_p3;
+ANALYZE prt2;
+ANALYZE prt2_p1;
+ANALYZE prt2_p2;
+ANALYZE prt2_p3;
+ANALYZE prt1_e;
+ANALYZE prt1_e_p1;
+ANALYZE prt1_e_p2;
+ANALYZE prt1_e_p3;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                             QUERY PLAN                                              
+-----------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Merge Left Join
+                     Output: t3.a, t3.b, t3.c, t2.b, t2.c, t1.a, t1.c
+                     Merge Cond: (t2.b = t1.a)
+                     ->  Sort
+                           Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                           Sort Key: t2.b
+                           ->  Merge Left Join
+                                 Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                                 Merge Cond: ((((t3.a + t3.b) / 2)) = t2.b)
+                                 ->  Sort
+                                       Output: t3.a, t3.b, t3.c, (((t3.a + t3.b) / 2))
+                                       Sort Key: (((t3.a + t3.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c, ((t3.a + t3.b) / 2)
+                                             Filter: ((t3.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t2.b, t2.c
+                                       Sort Key: t2.b
+                                       ->  Seq Scan on public.prt2_p1 t2
+                                             Output: t2.b, t2.c
+                     ->  Sort
+                           Output: t1.a, t1.c
+                           Sort Key: t1.a
+                           ->  Seq Scan on public.prt1_p1 t1
+                                 Output: t1.a, t1.c
+               ->  Merge Left Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c, t1_2.a, t1_2.c
+                     Merge Cond: (t2_1.b = t1_2.a)
+                     ->  Sort
+                           Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                           Sort Key: t2_1.b
+                           ->  Merge Left Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                                 Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t2_1.b)
+                                 ->  Sort
+                                       Output: t3_1.a, t3_1.b, t3_1.c, (((t3_1.a + t3_1.b) / 2))
+                                       Sort Key: (((t3_1.a + t3_1.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c, ((t3_1.a + t3_1.b) / 2)
+                                             Filter: ((t3_1.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t2_1.b, t2_1.c
+                                       Sort Key: t2_1.b
+                                       ->  Seq Scan on public.prt2_p2 t2_1
+                                             Output: t2_1.b, t2_1.c
+                     ->  Sort
+                           Output: t1_2.a, t1_2.c
+                           Sort Key: t1_2.a
+                           ->  Seq Scan on public.prt1_p2 t1_2
+                                 Output: t1_2.a, t1_2.c
+               ->  Merge Left Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c, t1_1.a, t1_1.c
+                     Merge Cond: (t2_2.b = t1_1.a)
+                     ->  Sort
+                           Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                           Sort Key: t2_2.b
+                           ->  Merge Left Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                                 Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t2_2.b)
+                                 ->  Sort
+                                       Output: t3_2.a, t3_2.b, t3_2.c, (((t3_2.a + t3_2.b) / 2))
+                                       Sort Key: (((t3_2.a + t3_2.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c, ((t3_2.a + t3_2.b) / 2)
+                                             Filter: ((t3_2.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t2_2.b, t2_2.c
+                                       Sort Key: t2_2.b
+                                       ->  Seq Scan on public.prt2_p3 t2_2
+                                             Output: t2_2.b, t2_2.c
+                     ->  Sort
+                           Output: t1_1.a, t1_1.c
+                           Sort Key: t1_1.a
+                           ->  Seq Scan on public.prt1_p3 t1_1
+                                 Output: t1_1.a, t1_1.c
+(81 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+                                   QUERY PLAN                                    
+---------------------------------------------------------------------------------
+ Merge Append
+   Sort Key: t1.a
+   ->  Merge Semi Join
+         Output: t1.a, t1.b, t1.c
+         Merge Cond: (t1.a = t1_3.b)
+         ->  Sort
+               Output: t1.a, t1.b, t1.c
+               Sort Key: t1.a
+               ->  Seq Scan on public.prt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+         ->  Materialize
+               Output: t1_3.b, t1_6.a, t1_6.b
+               ->  Merge Semi Join
+                     Output: t1_3.b, t1_6.a, t1_6.b
+                     Merge Cond: (t1_3.b = (((t1_6.a + t1_6.b) / 2)))
+                     ->  Sort
+                           Output: t1_3.b
+                           Sort Key: t1_3.b
+                           ->  Seq Scan on public.prt2_p1 t1_3
+                                 Output: t1_3.b
+                     ->  Sort
+                           Output: t1_6.a, t1_6.b, (((t1_6.a + t1_6.b) / 2))
+                           Sort Key: (((t1_6.a + t1_6.b) / 2))
+                           ->  Seq Scan on public.prt1_e_p1 t1_6
+                                 Output: t1_6.a, t1_6.b, ((t1_6.a + t1_6.b) / 2)
+                                 Filter: ((t1_6.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_2.a, t1_2.b, t1_2.c
+         Merge Cond: (t1_2.a = t1_4.b)
+         ->  Sort
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Sort Key: t1_2.a
+               ->  Seq Scan on public.prt1_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+         ->  Materialize
+               Output: t1_4.b, t1_7.a, t1_7.b
+               ->  Merge Semi Join
+                     Output: t1_4.b, t1_7.a, t1_7.b
+                     Merge Cond: (t1_4.b = (((t1_7.a + t1_7.b) / 2)))
+                     ->  Sort
+                           Output: t1_4.b
+                           Sort Key: t1_4.b
+                           ->  Seq Scan on public.prt2_p2 t1_4
+                                 Output: t1_4.b
+                     ->  Sort
+                           Output: t1_7.a, t1_7.b, (((t1_7.a + t1_7.b) / 2))
+                           Sort Key: (((t1_7.a + t1_7.b) / 2))
+                           ->  Seq Scan on public.prt1_e_p2 t1_7
+                                 Output: t1_7.a, t1_7.b, ((t1_7.a + t1_7.b) / 2)
+                                 Filter: ((t1_7.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_1.a, t1_1.b, t1_1.c
+         Merge Cond: (t1_1.a = t1_5.b)
+         ->  Sort
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Sort Key: t1_1.a
+               ->  Seq Scan on public.prt1_p3 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+         ->  Materialize
+               Output: t1_5.b, t1_8.a, t1_8.b
+               ->  Merge Semi Join
+                     Output: t1_5.b, t1_8.a, t1_8.b
+                     Merge Cond: (t1_5.b = (((t1_8.a + t1_8.b) / 2)))
+                     ->  Sort
+                           Output: t1_5.b
+                           Sort Key: t1_5.b
+                           ->  Seq Scan on public.prt2_p3 t1_5
+                                 Output: t1_5.b
+                     ->  Sort
+                           Output: t1_8.a, t1_8.b, (((t1_8.a + t1_8.b) / 2))
+                           Sort Key: (((t1_8.a + t1_8.b) / 2))
+                           ->  Seq Scan on public.prt1_e_p3 t1_8
+                                 Output: t1_8.a, t1_8.b, ((t1_8.a + t1_8.b) / 2)
+                                 Filter: ((t1_8.a % 25) = 0)
+(77 rows)
+
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                             QUERY PLAN                                              
+-----------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Merge Left Join
+                     Output: t3.a, t3.b, t3.c, t1.a, t1.c, t2.b, t2.c
+                     Merge Cond: (t1.a = t2.b)
+                     ->  Sort
+                           Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                           Sort Key: t1.a
+                           ->  Merge Left Join
+                                 Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                                 Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a)
+                                 ->  Sort
+                                       Output: t3.a, t3.b, t3.c, (((t3.a + t3.b) / 2))
+                                       Sort Key: (((t3.a + t3.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c, ((t3.a + t3.b) / 2)
+                                             Filter: ((t3.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t1.a, t1.c
+                                       Sort Key: t1.a
+                                       ->  Seq Scan on public.prt1_p1 t1
+                                             Output: t1.a, t1.c
+                     ->  Sort
+                           Output: t2.b, t2.c
+                           Sort Key: t2.b
+                           ->  Seq Scan on public.prt2_p1 t2
+                                 Output: t2.b, t2.c
+               ->  Merge Left Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                     Merge Cond: (t1_2.a = t2_1.b)
+                     ->  Sort
+                           Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                           Sort Key: t1_2.a
+                           ->  Merge Left Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                                 Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_2.a)
+                                 ->  Sort
+                                       Output: t3_1.a, t3_1.b, t3_1.c, (((t3_1.a + t3_1.b) / 2))
+                                       Sort Key: (((t3_1.a + t3_1.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c, ((t3_1.a + t3_1.b) / 2)
+                                             Filter: ((t3_1.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t1_2.a, t1_2.c
+                                       Sort Key: t1_2.a
+                                       ->  Seq Scan on public.prt1_p2 t1_2
+                                             Output: t1_2.a, t1_2.c
+                     ->  Sort
+                           Output: t2_1.b, t2_1.c
+                           Sort Key: t2_1.b
+                           ->  Seq Scan on public.prt2_p2 t2_1
+                                 Output: t2_1.b, t2_1.c
+               ->  Merge Left Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                     Merge Cond: (t1_1.a = t2_2.b)
+                     ->  Sort
+                           Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                           Sort Key: t1_1.a
+                           ->  Merge Left Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                                 Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_1.a)
+                                 ->  Sort
+                                       Output: t3_2.a, t3_2.b, t3_2.c, (((t3_2.a + t3_2.b) / 2))
+                                       Sort Key: (((t3_2.a + t3_2.b) / 2))
+                                       ->  Seq Scan on public.prt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c, ((t3_2.a + t3_2.b) / 2)
+                                             Filter: ((t3_2.a % 25) = 0)
+                                 ->  Sort
+                                       Output: t1_1.a, t1_1.c
+                                       Sort Key: t1_1.a
+                                       ->  Seq Scan on public.prt1_p3 t1_1
+                                             Output: t1_1.a, t1_1.c
+                     ->  Sort
+                           Output: t2_2.b, t2_2.c
+                           Sort Key: t2_2.b
+                           ->  Seq Scan on public.prt2_p3 t2_2
+                                 Output: t2_2.b, t2_2.c
+(81 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+SET enable_seqscan TO off;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                          QUERY PLAN                                          
+----------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Merge Left Join
+                     Output: t3.a, t3.b, t3.c, t2.b, t2.c, t1.a, t1.c
+                     Merge Cond: (t2.b = t1.a)
+                     ->  Sort
+                           Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                           Sort Key: t2.b
+                           ->  Merge Left Join
+                                 Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                                 Merge Cond: (((t3.a + t3.b) / 2) = t2.b)
+                                 ->  Index Scan using iprt1_e_p1_ab2 on public.prt1_e_p1 t3
+                                       Output: t3.a, t3.b, t3.c
+                                       Filter: ((t3.a % 25) = 0)
+                                 ->  Index Scan using iprt2_p1_b on public.prt2_p1 t2
+                                       Output: t2.b, t2.c
+                     ->  Index Scan using iprt1_p1_a on public.prt1_p1 t1
+                           Output: t1.a, t1.c
+               ->  Merge Left Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c, t1_2.a, t1_2.c
+                     Merge Cond: (t2_1.b = t1_2.a)
+                     ->  Sort
+                           Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                           Sort Key: t2_1.b
+                           ->  Merge Left Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                                 Merge Cond: (((t3_1.a + t3_1.b) / 2) = t2_1.b)
+                                 ->  Index Scan using iprt1_e_p2_ab2 on public.prt1_e_p2 t3_1
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       Filter: ((t3_1.a % 25) = 0)
+                                 ->  Index Scan using iprt2_p2_b on public.prt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                     ->  Index Scan using iprt1_p2_a on public.prt1_p2 t1_2
+                           Output: t1_2.a, t1_2.c
+               ->  Merge Right Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c, t1_1.a, t1_1.c
+                     Merge Cond: (t2_2.b = ((t3_2.a + t3_2.b) / 2))
+                     ->  Merge Left Join
+                           Output: t2_2.b, t2_2.c, t1_1.a, t1_1.c
+                           Merge Cond: (t2_2.b = t1_1.a)
+                           ->  Index Scan using iprt2_p3_b on public.prt2_p3 t2_2
+                                 Output: t2_2.b, t2_2.c
+                           ->  Index Scan using iprt1_p3_a on public.prt1_p3 t1_1
+                                 Output: t1_1.a, t1_1.c
+                     ->  Index Scan using iprt1_e_p3_ab2 on public.prt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                           Filter: ((t3_2.a % 25) = 0)
+(51 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+     |      |     |      |      100 | 0050
+     |      |     |      |      200 | 0100
+     |      |     |      |      400 | 0200
+     |      |     |      |      500 | 0250
+     |      |     |      |      700 | 0350
+     |      |     |      |      800 | 0400
+     |      |     |      |     1000 | 0500
+     |      |     |      |     1100 | 0550
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+                                    QUERY PLAN                                    
+----------------------------------------------------------------------------------
+ Merge Append
+   Sort Key: t1.a
+   ->  Merge Semi Join
+         Output: t1.a, t1.b, t1.c
+         Merge Cond: (t1.a = t1_3.b)
+         ->  Index Scan using iprt1_p1_a on public.prt1_p1 t1
+               Output: t1.a, t1.b, t1.c
+               Filter: ((t1.a % 25) = 0)
+         ->  Materialize
+               Output: t1_3.b, t1_6.a, t1_6.b
+               ->  Merge Semi Join
+                     Output: t1_3.b, t1_6.a, t1_6.b
+                     Merge Cond: (t1_3.b = ((t1_6.a + t1_6.b) / 2))
+                     ->  Index Only Scan using iprt2_p1_b on public.prt2_p1 t1_3
+                           Output: t1_3.b
+                     ->  Index Scan using iprt1_e_p1_ab2 on public.prt1_e_p1 t1_6
+                           Output: t1_6.a, t1_6.b
+                           Filter: ((t1_6.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_2.a, t1_2.b, t1_2.c
+         Merge Cond: (t1_2.a = t1_4.b)
+         ->  Index Scan using iprt1_p2_a on public.prt1_p2 t1_2
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Filter: ((t1_2.a % 25) = 0)
+         ->  Materialize
+               Output: t1_4.b, t1_7.a, t1_7.b
+               ->  Merge Semi Join
+                     Output: t1_4.b, t1_7.a, t1_7.b
+                     Merge Cond: (t1_4.b = ((t1_7.a + t1_7.b) / 2))
+                     ->  Index Only Scan using iprt2_p2_b on public.prt2_p2 t1_4
+                           Output: t1_4.b
+                     ->  Index Scan using iprt1_e_p2_ab2 on public.prt1_e_p2 t1_7
+                           Output: t1_7.a, t1_7.b
+                           Filter: ((t1_7.a % 25) = 0)
+   ->  Merge Semi Join
+         Output: t1_1.a, t1_1.b, t1_1.c
+         Merge Cond: (t1_1.a = t1_5.b)
+         ->  Index Scan using iprt1_p3_a on public.prt1_p3 t1_1
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Filter: ((t1_1.a % 25) = 0)
+         ->  Materialize
+               Output: t1_5.b, t1_8.a, t1_8.b
+               ->  Merge Semi Join
+                     Output: t1_5.b, t1_8.a, t1_8.b
+                     Merge Cond: (t1_5.b = ((t1_8.a + t1_8.b) / 2))
+                     ->  Index Only Scan using iprt2_p3_b on public.prt2_p3 t1_5
+                           Output: t1_5.b
+                     ->  Index Scan using iprt1_e_p3_ab2 on public.prt1_e_p3 t1_8
+                           Output: t1_8.a, t1_8.b
+                           Filter: ((t1_8.a % 25) = 0)
+(50 rows)
+
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+ 150 | 150 | 0150
+ 300 | 300 | 0300
+ 450 | 450 | 0450
+(4 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                          QUERY PLAN                                          
+----------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Merge Left Join
+                     Output: t3.a, t3.b, t3.c, t1.a, t1.c, t2.b, t2.c
+                     Merge Cond: (t1.a = t2.b)
+                     ->  Sort
+                           Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                           Sort Key: t1.a
+                           ->  Merge Left Join
+                                 Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                                 Merge Cond: (((t3.a + t3.b) / 2) = t1.a)
+                                 ->  Index Scan using iprt1_e_p1_ab2 on public.prt1_e_p1 t3
+                                       Output: t3.a, t3.b, t3.c
+                                       Filter: ((t3.a % 25) = 0)
+                                 ->  Index Scan using iprt1_p1_a on public.prt1_p1 t1
+                                       Output: t1.a, t1.c
+                     ->  Index Scan using iprt2_p1_b on public.prt2_p1 t2
+                           Output: t2.b, t2.c
+               ->  Merge Left Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c, t2_1.b, t2_1.c
+                     Merge Cond: (t1_2.a = t2_1.b)
+                     ->  Sort
+                           Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                           Sort Key: t1_2.a
+                           ->  Merge Left Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t1_2.a, t1_2.c
+                                 Merge Cond: (((t3_1.a + t3_1.b) / 2) = t1_2.a)
+                                 ->  Index Scan using iprt1_e_p2_ab2 on public.prt1_e_p2 t3_1
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       Filter: ((t3_1.a % 25) = 0)
+                                 ->  Index Scan using iprt1_p2_a on public.prt1_p2 t1_2
+                                       Output: t1_2.a, t1_2.c
+                     ->  Index Scan using iprt2_p2_b on public.prt2_p2 t2_1
+                           Output: t2_1.b, t2_1.c
+               ->  Merge Left Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c, t2_2.b, t2_2.c
+                     Merge Cond: (t1_1.a = t2_2.b)
+                     ->  Sort
+                           Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                           Sort Key: t1_1.a
+                           ->  Merge Left Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t1_1.a, t1_1.c
+                                 Merge Cond: (((t3_2.a + t3_2.b) / 2) = t1_1.a)
+                                 ->  Index Scan using iprt1_e_p3_ab2 on public.prt1_e_p3 t3_2
+                                       Output: t3_2.a, t3_2.b, t3_2.c
+                                       Filter: ((t3_2.a % 25) = 0)
+                                 ->  Index Scan using iprt1_p3_a on public.prt1_p3 t1_1
+                                       Output: t1_1.a, t1_1.c
+                     ->  Index Scan using iprt2_p3_b on public.prt2_p3 t2_2
+                           Output: t2_2.b, t2_2.c
+(54 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |  c   
+-----+------+-----+------+----------+------
+   0 | 0000 |   0 | 0000 |        0 | 0000
+  50 | 0050 |     |      |      100 | 0050
+ 100 | 0100 |     |      |      200 | 0100
+ 150 | 0150 | 150 | 0150 |      300 | 0150
+ 200 | 0200 |     |      |      400 | 0200
+ 250 | 0250 |     |      |      500 | 0250
+ 300 | 0300 | 300 | 0300 |      600 | 0300
+ 350 | 0350 |     |      |      700 | 0350
+ 400 | 0400 |     |      |      800 | 0400
+ 450 | 0450 | 450 | 0450 |      900 | 0450
+ 500 | 0500 |     |      |     1000 | 0500
+ 550 | 0550 |     |      |     1100 | 0550
+(12 rows)
+
+-- lateral references and parameterized paths
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                          QUERY PLAN                                           
+-----------------------------------------------------------------------------------------------
+ Result
+   Output: t1.a, t1.b, t1.c, t2.a, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   ->  Merge Append
+         Sort Key: t1.a
+         ->  Nested Loop Left Join
+               Output: t1.a, t1.b, t1.c, t2.a, t3.a, (LEAST(t1.a, t2.a, t3.a))
+               ->  Index Scan using iprt1_p1_a on public.prt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Merge Join
+                     Output: t2.a, t3.a, LEAST(t1.a, t2.a, t3.a)
+                     Merge Cond: (t2.a = t3.b)
+                     ->  Index Only Scan using iprt1_p1_a on public.prt1_p1 t2
+                           Output: t2.a
+                           Index Cond: (t2.a = t1.a)
+                     ->  Index Scan using iprt2_p1_b on public.prt2_p1 t3
+                           Output: t3.a, t3.b
+         ->  Nested Loop Left Join
+               Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t3_1.a, (LEAST(t1_2.a, t2_2.a, t3_1.a))
+               ->  Index Scan using iprt1_p2_a on public.prt1_p2 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Merge Join
+                     Output: t2_2.a, t3_1.a, LEAST(t1_2.a, t2_2.a, t3_1.a)
+                     Merge Cond: (t2_2.a = t3_1.b)
+                     ->  Index Only Scan using iprt1_p2_a on public.prt1_p2 t2_2
+                           Output: t2_2.a
+                           Index Cond: (t2_2.a = t1_2.a)
+                     ->  Index Scan using iprt2_p2_b on public.prt2_p2 t3_1
+                           Output: t3_1.a, t3_1.b
+         ->  Nested Loop Left Join
+               Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t3_2.a, (LEAST(t1_1.a, t2_1.a, t3_2.a))
+               ->  Index Scan using iprt1_p3_a on public.prt1_p3 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Merge Join
+                     Output: t2_1.a, t3_2.a, LEAST(t1_1.a, t2_1.a, t3_2.a)
+                     Merge Cond: (t2_1.a = t3_2.b)
+                     ->  Index Only Scan using iprt1_p3_a on public.prt1_p3 t2_1
+                           Output: t2_1.a
+                           Index Cond: (t2_1.a = t1_1.a)
+                     ->  Index Scan using iprt2_p3_b on public.prt2_p3 t3_2
+                           Output: t3_2.a, t3_2.b
+(43 rows)
+
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Nested Loop Left Join
+   Output: t1.a, t1.b, t1.c, t2.a, t3.a, (LEAST(t1.a, t2.a, t3.a)), t1.a
+   ->  Merge Append
+         Sort Key: t1.a
+         ->  Sort
+               Output: t1.a, t1.b, t1.c
+               Sort Key: t1.a
+               ->  Seq Scan on public.prt1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+         ->  Index Scan using iprt1_p1_a on public.prt1_p1 t1_1
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Filter: ((t1_1.a % 25) = 0)
+         ->  Index Scan using iprt1_p3_a on public.prt1_p3 t1_2
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Filter: ((t1_2.a % 25) = 0)
+         ->  Index Scan using iprt1_p2_a on public.prt1_p2 t1_3
+               Output: t1_3.a, t1_3.b, t1_3.c
+               Filter: ((t1_3.a % 25) = 0)
+   ->  Append
+         ->  Merge Join
+               Output: t2.a, t3.a, LEAST(t1.a, t2.a, t3.a)
+               Merge Cond: (t2.a = t3.b)
+               ->  Index Only Scan using iprt1_p1_a on public.prt1_p1 t2
+                     Output: t2.a
+                     Index Cond: (t2.a = t1.b)
+               ->  Index Scan using iprt2_p1_b on public.prt2_p1 t3
+                     Output: t3.a, t3.b
+         ->  Merge Join
+               Output: t2_2.a, t3_1.a, LEAST(t1.a, t2_2.a, t3_1.a)
+               Merge Cond: (t2_2.a = t3_1.b)
+               ->  Index Only Scan using iprt1_p2_a on public.prt1_p2 t2_2
+                     Output: t2_2.a
+                     Index Cond: (t2_2.a = t1.b)
+               ->  Index Scan using iprt2_p2_b on public.prt2_p2 t3_1
+                     Output: t3_1.a, t3_1.b
+         ->  Merge Join
+               Output: t2_1.a, t3_2.a, LEAST(t1.a, t2_1.a, t3_2.a)
+               Merge Cond: (t2_1.a = t3_2.b)
+               ->  Index Only Scan using iprt1_p3_a on public.prt1_p3 t2_1
+                     Output: t2_1.a
+                     Index Cond: (t2_1.a = t1.b)
+               ->  Index Scan using iprt2_p3_b on public.prt2_p3 t3_2
+                     Output: t3_2.a, t3_2.b
+(44 rows)
+
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   | t2a | t3a | least 
+-----+-----+------+-----+-----+-------
+   0 |   0 | 0000 |   0 |   0 |     0
+  50 |  50 | 0050 |     |     |      
+ 100 | 100 | 0100 |     |     |      
+ 150 | 150 | 0150 | 150 | 150 |   150
+ 200 | 200 | 0200 |     |     |      
+ 250 | 250 | 0250 |     |     |      
+ 300 | 300 | 0300 | 300 | 300 |   300
+ 350 | 350 | 0350 |     |     |      
+ 400 | 400 | 0400 |     |     |      
+ 450 | 450 | 0450 | 450 | 450 |   450
+ 500 | 500 | 0500 |     |     |      
+ 550 | 550 | 0550 |     |     |      
+(12 rows)
+
+RESET enable_hashjoin;
+RESET enable_nestloop;
+RESET enable_seqscan;
+--
+-- partitioned by multiple columns
+--
+CREATE TABLE prt1_m (a int, b int, c varchar) PARTITION BY RANGE(a, ((a + b)/2));
+CREATE TABLE prt1_m_p1 PARTITION OF prt1_m FOR VALUES FROM (0, 0) TO (250, 250);
+CREATE TABLE prt1_m_p2 PARTITION OF prt1_m FOR VALUES FROM (250, 250) TO (500, 500);
+CREATE TABLE prt1_m_p3 PARTITION OF prt1_m FOR VALUES FROM (500, 500) TO (600, 600);
+INSERT INTO prt1_m SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_m;
+ANALYZE prt1_m_p1;
+ANALYZE prt1_m_p2;
+ANALYZE prt1_m_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_m AS SELECT * FROM prt1_m;
+CREATE TABLE prt2_m (a int, b int, c varchar) PARTITION BY RANGE(((b + a)/2), b);
+CREATE TABLE prt2_m_p1 PARTITION OF prt2_m FOR VALUES FROM (0, 0) TO (250, 250);
+CREATE TABLE prt2_m_p2 PARTITION OF prt2_m FOR VALUES FROM (250, 250) TO (500, 500);
+CREATE TABLE prt2_m_p3 PARTITION OF prt2_m FOR VALUES FROM (500, 500) TO (600, 600);
+INSERT INTO prt2_m SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_m;
+ANALYZE prt2_m_p1;
+ANALYZE prt2_m_p2;
+ANALYZE prt2_m_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_m AS SELECT * FROM prt2_m;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 RIGHT JOIN prt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 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 + t1.b) / 2) = t2.b) AND (t1.a = ((t2.b + t2.a) / 2)))
+                     ->  Seq Scan on public.prt1_m_p1 t1
+                           Output: t1.a, t1.c, t1.b
+                     ->  Hash
+                           Output: t2.b, t2.c, t2.a
+                           ->  Seq Scan on public.prt2_m_p1 t2
+                                 Output: t2.b, t2.c, t2.a
+                                 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 + t1_1.b) / 2) = t2_1.b) AND (t1_1.a = ((t2_1.b + t2_1.a) / 2)))
+                     ->  Seq Scan on public.prt1_m_p2 t1_1
+                           Output: t1_1.a, t1_1.c, t1_1.b
+                     ->  Hash
+                           Output: t2_1.b, t2_1.c, t2_1.a
+                           ->  Seq Scan on public.prt2_m_p2 t2_1
+                                 Output: t2_1.b, t2_1.c, t2_1.a
+                                 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 + t1_2.b) / 2) = t2_2.b) AND (t1_2.a = ((t2_2.b + t2_2.a) / 2)))
+                     ->  Seq Scan on public.prt1_m_p3 t1_2
+                           Output: t1_2.a, t1_2.c, t1_2.b
+                     ->  Hash
+                           Output: t2_2.b, t2_2.c, t2_2.a
+                           ->  Seq Scan on public.prt2_m_p3 t2_2
+                                 Output: t2_2.b, t2_2.c, t2_2.a
+                                 Filter: ((t2_2.b % 25) = 0)
+(36 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 RIGHT JOIN prt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 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_m t1 RIGHT JOIN uprt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 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)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) ORDER BY t1.a, t2.b;
+                                                             QUERY PLAN                                                             
+------------------------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: prt1_m_p1.a, prt1_m_p1.c, prt2_m_p1.b, prt2_m_p1.c
+   Sort Key: prt1_m_p1.a, prt2_m_p1.b
+   ->  Append
+         ->  Hash Full Join
+               Output: prt1_m_p1.a, prt1_m_p1.c, prt2_m_p1.b, prt2_m_p1.c
+               Hash Cond: ((prt1_m_p1.a = ((prt2_m_p1.b + prt2_m_p1.a) / 2)) AND (((prt1_m_p1.a + prt1_m_p1.b) / 2) = prt2_m_p1.b))
+               ->  Seq Scan on public.prt1_m_p1
+                     Output: prt1_m_p1.a, prt1_m_p1.c, prt1_m_p1.b
+                     Filter: ((prt1_m_p1.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_m_p1.b, prt2_m_p1.c, prt2_m_p1.a
+                     ->  Seq Scan on public.prt2_m_p1
+                           Output: prt2_m_p1.b, prt2_m_p1.c, prt2_m_p1.a
+                           Filter: ((prt2_m_p1.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_m_p2.a, prt1_m_p2.c, prt2_m_p2.b, prt2_m_p2.c
+               Hash Cond: ((prt1_m_p2.a = ((prt2_m_p2.b + prt2_m_p2.a) / 2)) AND (((prt1_m_p2.a + prt1_m_p2.b) / 2) = prt2_m_p2.b))
+               ->  Seq Scan on public.prt1_m_p2
+                     Output: prt1_m_p2.a, prt1_m_p2.c, prt1_m_p2.b
+                     Filter: ((prt1_m_p2.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_m_p2.b, prt2_m_p2.c, prt2_m_p2.a
+                     ->  Seq Scan on public.prt2_m_p2
+                           Output: prt2_m_p2.b, prt2_m_p2.c, prt2_m_p2.a
+                           Filter: ((prt2_m_p2.b % 25) = 0)
+         ->  Hash Full Join
+               Output: prt1_m_p3.a, prt1_m_p3.c, prt2_m_p3.b, prt2_m_p3.c
+               Hash Cond: ((prt1_m_p3.a = ((prt2_m_p3.b + prt2_m_p3.a) / 2)) AND (((prt1_m_p3.a + prt1_m_p3.b) / 2) = prt2_m_p3.b))
+               ->  Seq Scan on public.prt1_m_p3
+                     Output: prt1_m_p3.a, prt1_m_p3.c, prt1_m_p3.b
+                     Filter: ((prt1_m_p3.a % 25) = 0)
+               ->  Hash
+                     Output: prt2_m_p3.b, prt2_m_p3.c, prt2_m_p3.a
+                     ->  Seq Scan on public.prt2_m_p3
+                           Output: prt2_m_p3.b, prt2_m_p3.c, prt2_m_p3.a
+                           Filter: ((prt2_m_p3.b % 25) = 0)
+(37 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) 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_m t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_m t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) 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)
+
+--
+-- tests for list partitioned tables.
+--
+CREATE TABLE plt1 (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE plt1;
+ANALYZE plt1_p1;
+ANALYZE plt1_p2;
+ANALYZE plt1_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt1 AS SELECT * FROM plt1;
+CREATE TABLE plt2 (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE plt2;
+ANALYZE plt2_p1;
+ANALYZE plt2_p2;
+ANALYZE plt2_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt2 AS SELECT * FROM plt2;
+--
+-- list partitioned by expression
+--
+CREATE TABLE plt1_e (a int, b int, c text) PARTITION BY LIST(ltrim(c, 'A'));
+CREATE TABLE plt1_e_p1 PARTITION OF plt1_e FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt1_e SELECT i, i, 'A' || to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE plt1_e;
+ANALYZE plt1_e_p1;
+ANALYZE plt1_e_p2;
+ANALYZE plt1_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt1_e AS SELECT * FROM plt1_e;
+--
+-- N-way join
+--
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+                                        QUERY PLAN                                        
+------------------------------------------------------------------------------------------
+ Sort
+   Output: (avg(t1.a)), (avg(t2.b)), (avg((t3.a + t3.b))), t1.c, t2.c, t3.c
+   Sort Key: t1.c, t3.c
+   ->  HashAggregate
+         Output: avg(t1.a), avg(t2.b), avg((t3.a + t3.b)), t1.c, t2.c, t3.c
+         Group Key: t1.c, t2.c, t3.c
+         ->  Result
+               Output: t1.c, t2.c, t3.c, t1.a, t2.b, t3.a, t3.b
+               ->  Append
+                     ->  Hash Join
+                           Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                           Hash Cond: (t1.c = t2.c)
+                           ->  Seq Scan on public.plt1_p1 t1
+                                 Output: t1.a, t1.c
+                           ->  Hash
+                                 Output: t2.b, t2.c, t3.a, t3.b, t3.c
+                                 ->  Hash Join
+                                       Output: t2.b, t2.c, t3.a, t3.b, t3.c
+                                       Hash Cond: (t2.c = ltrim(t3.c, 'A'::text))
+                                       ->  Seq Scan on public.plt2_p1 t2
+                                             Output: t2.b, t2.c
+                                       ->  Hash
+                                             Output: t3.a, t3.b, t3.c
+                                             ->  Seq Scan on public.plt1_e_p1 t3
+                                                   Output: t3.a, t3.b, t3.c
+                     ->  Hash Join
+                           Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                           Hash Cond: (t1_1.c = t2_1.c)
+                           ->  Seq Scan on public.plt1_p2 t1_1
+                                 Output: t1_1.a, t1_1.c
+                           ->  Hash
+                                 Output: t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                                 ->  Hash Join
+                                       Output: t2_1.b, t2_1.c, t3_1.a, t3_1.b, t3_1.c
+                                       Hash Cond: (t2_1.c = ltrim(t3_1.c, 'A'::text))
+                                       ->  Seq Scan on public.plt2_p2 t2_1
+                                             Output: t2_1.b, t2_1.c
+                                       ->  Hash
+                                             Output: t3_1.a, t3_1.b, t3_1.c
+                                             ->  Seq Scan on public.plt1_e_p2 t3_1
+                                                   Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash Join
+                           Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                           Hash Cond: (t1_2.c = t2_2.c)
+                           ->  Seq Scan on public.plt1_p3 t1_2
+                                 Output: t1_2.a, t1_2.c
+                           ->  Hash
+                                 Output: t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                                 ->  Hash Join
+                                       Output: t2_2.b, t2_2.c, t3_2.a, t3_2.b, t3_2.c
+                                       Hash Cond: (t2_2.c = ltrim(t3_2.c, 'A'::text))
+                                       ->  Seq Scan on public.plt2_p3 t2_2
+                                             Output: t2_2.b, t2_2.c
+                                       ->  Hash
+                                             Output: t3_2.a, t3_2.b, t3_2.c
+                                             ->  Seq Scan on public.plt1_e_p3 t3_2
+                                                   Output: t3_2.a, t3_2.b, t3_2.c
+(57 rows)
+
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+         avg          |         avg          |          avg          |  c   |  c   |   c   
+----------------------+----------------------+-----------------------+------+------+-------
+  24.0000000000000000 |  24.0000000000000000 |   48.0000000000000000 | 0000 | 0000 | A0000
+  74.0000000000000000 |  75.0000000000000000 |  148.0000000000000000 | 0001 | 0001 | A0001
+ 124.0000000000000000 | 124.5000000000000000 |  248.0000000000000000 | 0002 | 0002 | A0002
+ 174.0000000000000000 | 174.0000000000000000 |  348.0000000000000000 | 0003 | 0003 | A0003
+ 224.0000000000000000 | 225.0000000000000000 |  448.0000000000000000 | 0004 | 0004 | A0004
+ 274.0000000000000000 | 274.5000000000000000 |  548.0000000000000000 | 0005 | 0005 | A0005
+ 324.0000000000000000 | 324.0000000000000000 |  648.0000000000000000 | 0006 | 0006 | A0006
+ 374.0000000000000000 | 375.0000000000000000 |  748.0000000000000000 | 0007 | 0007 | A0007
+ 424.0000000000000000 | 424.5000000000000000 |  848.0000000000000000 | 0008 | 0008 | A0008
+ 474.0000000000000000 | 474.0000000000000000 |  948.0000000000000000 | 0009 | 0009 | A0009
+ 524.0000000000000000 | 525.0000000000000000 | 1048.0000000000000000 | 0010 | 0010 | A0010
+ 574.0000000000000000 | 574.5000000000000000 | 1148.0000000000000000 | 0011 | 0011 | A0011
+(12 rows)
+
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM uplt1 t1, uplt2 t2, uplt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+         avg          |         avg          |          avg          |  c   |  c   |   c   
+----------------------+----------------------+-----------------------+------+------+-------
+  24.0000000000000000 |  24.0000000000000000 |   48.0000000000000000 | 0000 | 0000 | A0000
+  74.0000000000000000 |  75.0000000000000000 |  148.0000000000000000 | 0001 | 0001 | A0001
+ 124.0000000000000000 | 124.5000000000000000 |  248.0000000000000000 | 0002 | 0002 | A0002
+ 174.0000000000000000 | 174.0000000000000000 |  348.0000000000000000 | 0003 | 0003 | A0003
+ 224.0000000000000000 | 225.0000000000000000 |  448.0000000000000000 | 0004 | 0004 | A0004
+ 274.0000000000000000 | 274.5000000000000000 |  548.0000000000000000 | 0005 | 0005 | A0005
+ 324.0000000000000000 | 324.0000000000000000 |  648.0000000000000000 | 0006 | 0006 | A0006
+ 374.0000000000000000 | 375.0000000000000000 |  748.0000000000000000 | 0007 | 0007 | A0007
+ 424.0000000000000000 | 424.5000000000000000 |  848.0000000000000000 | 0008 | 0008 | A0008
+ 474.0000000000000000 | 474.0000000000000000 |  948.0000000000000000 | 0009 | 0009 | A0009
+ 524.0000000000000000 | 525.0000000000000000 | 1048.0000000000000000 | 0010 | 0010 | A0010
+ 574.0000000000000000 | 574.5000000000000000 | 1148.0000000000000000 | 0011 | 0011 | A0011
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                         QUERY PLAN                                         
+--------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                     Hash Cond: ((t3.a = t1.a) AND (ltrim(t3.c, 'A'::text) = t1.c))
+                     ->  Seq Scan on public.plt1_e_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t1.a, t1.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t1.a, t1.c, t2.b, t2.c
+                                 Hash Cond: ((t2.b = t1.a) AND (t2.c = t1.c))
+                                 ->  Seq Scan on public.plt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t1.a, t1.c
+                                       ->  Seq Scan on public.plt1_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, t3_1.a, t3_1.b, t3_1.c
+                     Hash Cond: ((t3_1.a = t1_1.a) AND (ltrim(t3_1.c, 'A'::text) = t1_1.c))
+                     ->  Seq Scan on public.plt1_e_p2 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
+                           ->  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 = t1_1.c))
+                                 ->  Seq Scan on public.plt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t1_1.a, t1_1.c
+                                       ->  Seq Scan on public.plt1_p2 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, t3_2.a, t3_2.b, t3_2.c
+                     Hash Cond: ((t3_2.a = t1_2.a) AND (ltrim(t3_2.c, 'A'::text) = t1_2.c))
+                     ->  Seq Scan on public.plt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
+                           ->  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 = t1_2.c))
+                                 ->  Seq Scan on public.plt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t1_2.a, t1_2.c
+                                       ->  Seq Scan on public.plt1_p3 t1_2
+                                             Output: t1_2.a, t1_2.c
+                                             Filter: ((t1_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN uplt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                         QUERY PLAN                                         
+--------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t1.a, t1.c, t2.b, t2.c, t3.a, t3.b, t3.c
+                     Hash Cond: ((t3.a = t2.b) AND (ltrim(t3.c, 'A'::text) = t2.c))
+                     ->  Seq Scan on public.plt1_e_p1 t3
+                           Output: t3.a, t3.b, t3.c
+                     ->  Hash
+                           Output: t1.a, t1.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t1.a, t1.c, t2.b, t2.c
+                                 Hash Cond: ((t2.b = t1.a) AND (t2.c = t1.c))
+                                 ->  Seq Scan on public.plt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t1.a, t1.c
+                                       ->  Seq Scan on public.plt1_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, t3_1.a, t3_1.b, t3_1.c
+                     Hash Cond: ((t3_1.a = t2_1.b) AND (ltrim(t3_1.c, 'A'::text) = t2_1.c))
+                     ->  Seq Scan on public.plt1_e_p2 t3_1
+                           Output: t3_1.a, t3_1.b, t3_1.c
+                     ->  Hash
+                           Output: t1_1.a, t1_1.c, t2_1.b, t2_1.c
+                           ->  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 = t1_1.c))
+                                 ->  Seq Scan on public.plt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t1_1.a, t1_1.c
+                                       ->  Seq Scan on public.plt1_p2 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, t3_2.a, t3_2.b, t3_2.c
+                     Hash Cond: ((t3_2.a = t2_2.b) AND (ltrim(t3_2.c, 'A'::text) = t2_2.c))
+                     ->  Seq Scan on public.plt1_e_p3 t3_2
+                           Output: t3_2.a, t3_2.b, t3_2.c
+                     ->  Hash
+                           Output: t1_2.a, t1_2.c, t2_2.b, t2_2.c
+                           ->  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 = t1_2.c))
+                                 ->  Seq Scan on public.plt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t1_2.a, t1_2.c
+                                       ->  Seq Scan on public.plt1_p3 t1_2
+                                             Output: t1_2.a, t1_2.c
+                                             Filter: ((t1_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |          | 
+ 100 | 0002 |     |      |          | 
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |          | 
+ 250 | 0005 |     |      |          | 
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |          | 
+ 400 | 0008 |     |      |          | 
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |          | 
+ 550 | 0011 |     |      |          | 
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN uplt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |          | 
+ 100 | 0002 |     |      |          | 
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |          | 
+ 250 | 0005 |     |      |          | 
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |          | 
+ 400 | 0008 |     |      |          | 
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |          | 
+ 550 | 0011 |     |      |          | 
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                               QUERY PLAN                                               
+--------------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t3.a, t3.b, t3.c, t1.a, t1.c, t2.b, t2.c
+                     Hash Cond: ((t2.b = t1.a) AND (t2.c = t1.c))
+                     ->  Seq Scan on public.plt2_p1 t2
+                           Output: t2.b, t2.c
+                     ->  Hash
+                           Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                           ->  Hash Right Join
+                                 Output: t3.a, t3.b, t3.c, t1.a, t1.c
+                                 Hash Cond: ((t1.c = ltrim(t3.c, 'A'::text)) AND (t1.a = t3.a))
+                                 ->  Seq Scan on public.plt1_p1 t1
+                                       Output: t1.a, t1.c
+                                 ->  Hash
+                                       Output: t3.a, t3.b, t3.c
+                                       ->  Seq Scan on public.plt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c
+                                             Filter: ((t3.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t1_1.a, t1_1.c, t2_1.b, t2_1.c
+                     Hash Cond: ((t2_1.b = t1_1.a) AND (t2_1.c = t1_1.c))
+                     ->  Seq Scan on public.plt2_p2 t2_1
+                           Output: t2_1.b, t2_1.c
+                     ->  Hash
+                           Output: t3_1.a, t3_1.b, t3_1.c, t1_1.a, t1_1.c
+                           ->  Hash Right Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t1_1.a, t1_1.c
+                                 Hash Cond: ((t1_1.c = ltrim(t3_1.c, 'A'::text)) AND (t1_1.a = t3_1.a))
+                                 ->  Seq Scan on public.plt1_p2 t1_1
+                                       Output: t1_1.a, t1_1.c
+                                 ->  Hash
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       ->  Seq Scan on public.plt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c
+                                             Filter: ((t3_1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t1_2.a, t1_2.c, t2_2.b, t2_2.c
+                     Hash Cond: ((t2_2.b = t1_2.a) AND (t2_2.c = t1_2.c))
+                     ->  Seq Scan on public.plt2_p3 t2_2
+                           Output: t2_2.b, t2_2.c
+                     ->  Hash
+                           Output: t3_2.a, t3_2.b, t3_2.c, t1_2.a, t1_2.c
+                           ->  Hash Right Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t1_2.a, t1_2.c
+                                 Hash Cond: ((t1_2.c = ltrim(t3_2.c, 'A'::text)) AND (t1_2.a = t3_2.a))
+                                 ->  Seq Scan on public.plt1_p3 t1_2
+                                       Output: t1_2.a, t1_2.c
+                                 ->  Hash
+                                       Output: t3_2.a, t3_2.b, t3_2.c
+                                       ->  Seq Scan on public.plt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c
+                                             Filter: ((t3_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN uplt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 RIGHT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                               QUERY PLAN                                               
+--------------------------------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.c, t2.b, t2.c, ((t3.a + t3.b)), t3.c
+   Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+   ->  Result
+         Output: t1.a, t1.c, t2.b, t2.c, (t3.a + t3.b), t3.c
+         ->  Append
+               ->  Hash Right Join
+                     Output: t3.a, t3.b, t3.c, t2.b, t2.c, t1.a, t1.c
+                     Hash Cond: ((t1.a = t2.b) AND (t1.c = t2.c))
+                     ->  Seq Scan on public.plt1_p1 t1
+                           Output: t1.a, t1.c
+                     ->  Hash
+                           Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                           ->  Hash Right Join
+                                 Output: t3.a, t3.b, t3.c, t2.b, t2.c
+                                 Hash Cond: ((t2.b = t3.a) AND (t2.c = ltrim(t3.c, 'A'::text)))
+                                 ->  Seq Scan on public.plt2_p1 t2
+                                       Output: t2.b, t2.c
+                                 ->  Hash
+                                       Output: t3.a, t3.b, t3.c
+                                       ->  Seq Scan on public.plt1_e_p1 t3
+                                             Output: t3.a, t3.b, t3.c
+                                             Filter: ((t3.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c, t1_1.a, t1_1.c
+                     Hash Cond: ((t1_1.a = t2_1.b) AND (t1_1.c = t2_1.c))
+                     ->  Seq Scan on public.plt1_p2 t1_1
+                           Output: t1_1.a, t1_1.c
+                     ->  Hash
+                           Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                           ->  Hash Right Join
+                                 Output: t3_1.a, t3_1.b, t3_1.c, t2_1.b, t2_1.c
+                                 Hash Cond: ((t2_1.b = t3_1.a) AND (t2_1.c = ltrim(t3_1.c, 'A'::text)))
+                                 ->  Seq Scan on public.plt2_p2 t2_1
+                                       Output: t2_1.b, t2_1.c
+                                 ->  Hash
+                                       Output: t3_1.a, t3_1.b, t3_1.c
+                                       ->  Seq Scan on public.plt1_e_p2 t3_1
+                                             Output: t3_1.a, t3_1.b, t3_1.c
+                                             Filter: ((t3_1.a % 25) = 0)
+               ->  Hash Right Join
+                     Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c, t1_2.a, t1_2.c
+                     Hash Cond: ((t1_2.a = t2_2.b) AND (t1_2.c = t2_2.c))
+                     ->  Seq Scan on public.plt1_p3 t1_2
+                           Output: t1_2.a, t1_2.c
+                     ->  Hash
+                           Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                           ->  Hash Right Join
+                                 Output: t3_2.a, t3_2.b, t3_2.c, t2_2.b, t2_2.c
+                                 Hash Cond: ((t2_2.b = t3_2.a) AND (t2_2.c = ltrim(t3_2.c, 'A'::text)))
+                                 ->  Seq Scan on public.plt2_p3 t2_2
+                                       Output: t2_2.b, t2_2.c
+                                 ->  Hash
+                                       Output: t3_2.a, t3_2.b, t3_2.c
+                                       ->  Seq Scan on public.plt1_e_p3 t3_2
+                                             Output: t3_2.a, t3_2.b, t3_2.c
+                                             Filter: ((t3_2.a % 25) = 0)
+(57 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 RIGHT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+     |      |     |      |      100 | A0001
+     |      |     |      |      200 | A0002
+     |      |     |      |      400 | A0004
+     |      |     |      |      500 | A0005
+     |      |     |      |      700 | A0007
+     |      |     |      |      800 | A0008
+     |      |     |      |     1000 | A0010
+     |      |     |      |     1100 | A0011
+(12 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 RIGHT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN uplt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+     |      |     |      |      100 | A0001
+     |      |     |      |      200 | A0002
+     |      |     |      |      400 | A0004
+     |      |     |      |      500 | A0005
+     |      |     |      |      700 | A0007
+     |      |     |      |      800 | A0008
+     |      |     |      |     1000 | A0010
+     |      |     |      |     1100 | A0011
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM plt1 WHERE plt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM plt2 WHERE plt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM plt1_e WHERE plt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+                                                  QUERY PLAN                                                   
+---------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: plt1_p1.a, plt1_p1.c, plt2_p1.b, plt2_p1.c, ((plt1_e_p1.a + plt1_e_p1.b)), plt1_e_p1.c
+   Sort Key: plt1_p1.a, plt2_p1.b, ((plt1_e_p1.a + plt1_e_p1.b))
+   ->  Result
+         Output: plt1_p1.a, plt1_p1.c, plt2_p1.b, plt2_p1.c, (plt1_e_p1.a + plt1_e_p1.b), plt1_e_p1.c
+         ->  Append
+               ->  Hash Full Join
+                     Output: plt1_p1.a, plt1_p1.c, plt2_p1.b, plt2_p1.c, plt1_e_p1.a, plt1_e_p1.b, plt1_e_p1.c
+                     Hash Cond: ((plt1_p1.a = plt1_e_p1.a) AND (plt1_p1.c = ltrim(plt1_e_p1.c, 'A'::text)))
+                     ->  Hash Full Join
+                           Output: plt1_p1.a, plt1_p1.c, plt2_p1.b, plt2_p1.c
+                           Hash Cond: ((plt1_p1.a = plt2_p1.b) AND (plt1_p1.c = plt2_p1.c))
+                           ->  Seq Scan on public.plt1_p1
+                                 Output: plt1_p1.a, plt1_p1.c
+                                 Filter: ((plt1_p1.a % 25) = 0)
+                           ->  Hash
+                                 Output: plt2_p1.b, plt2_p1.c
+                                 ->  Seq Scan on public.plt2_p1
+                                       Output: plt2_p1.b, plt2_p1.c
+                                       Filter: ((plt2_p1.b % 25) = 0)
+                     ->  Hash
+                           Output: plt1_e_p1.a, plt1_e_p1.b, plt1_e_p1.c
+                           ->  Seq Scan on public.plt1_e_p1
+                                 Output: plt1_e_p1.a, plt1_e_p1.b, plt1_e_p1.c
+                                 Filter: ((plt1_e_p1.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: plt1_p2.a, plt1_p2.c, plt2_p2.b, plt2_p2.c, plt1_e_p2.a, plt1_e_p2.b, plt1_e_p2.c
+                     Hash Cond: ((plt1_p2.a = plt1_e_p2.a) AND (plt1_p2.c = ltrim(plt1_e_p2.c, 'A'::text)))
+                     ->  Hash Full Join
+                           Output: plt1_p2.a, plt1_p2.c, plt2_p2.b, plt2_p2.c
+                           Hash Cond: ((plt1_p2.a = plt2_p2.b) AND (plt1_p2.c = plt2_p2.c))
+                           ->  Seq Scan on public.plt1_p2
+                                 Output: plt1_p2.a, plt1_p2.c
+                                 Filter: ((plt1_p2.a % 25) = 0)
+                           ->  Hash
+                                 Output: plt2_p2.b, plt2_p2.c
+                                 ->  Seq Scan on public.plt2_p2
+                                       Output: plt2_p2.b, plt2_p2.c
+                                       Filter: ((plt2_p2.b % 25) = 0)
+                     ->  Hash
+                           Output: plt1_e_p2.a, plt1_e_p2.b, plt1_e_p2.c
+                           ->  Seq Scan on public.plt1_e_p2
+                                 Output: plt1_e_p2.a, plt1_e_p2.b, plt1_e_p2.c
+                                 Filter: ((plt1_e_p2.a % 25) = 0)
+               ->  Hash Full Join
+                     Output: plt1_p3.a, plt1_p3.c, plt2_p3.b, plt2_p3.c, plt1_e_p3.a, plt1_e_p3.b, plt1_e_p3.c
+                     Hash Cond: ((plt1_p3.a = plt1_e_p3.a) AND (plt1_p3.c = ltrim(plt1_e_p3.c, 'A'::text)))
+                     ->  Hash Full Join
+                           Output: plt1_p3.a, plt1_p3.c, plt2_p3.b, plt2_p3.c
+                           Hash Cond: ((plt1_p3.a = plt2_p3.b) AND (plt1_p3.c = plt2_p3.c))
+                           ->  Seq Scan on public.plt1_p3
+                                 Output: plt1_p3.a, plt1_p3.c
+                                 Filter: ((plt1_p3.a % 25) = 0)
+                           ->  Hash
+                                 Output: plt2_p3.b, plt2_p3.c
+                                 ->  Seq Scan on public.plt2_p3
+                                       Output: plt2_p3.b, plt2_p3.c
+                                       Filter: ((plt2_p3.b % 25) = 0)
+                     ->  Hash
+                           Output: plt1_e_p3.a, plt1_e_p3.b, plt1_e_p3.c
+                           ->  Seq Scan on public.plt1_e_p3
+                                 Output: plt1_e_p3.a, plt1_e_p3.b, plt1_e_p3.c
+                                 Filter: ((plt1_e_p3.a % 25) = 0)
+(63 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM plt1 WHERE plt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM plt2 WHERE plt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM plt1_e WHERE plt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+     |      |  75 | 0001 |          | 
+     |      | 225 | 0004 |          | 
+     |      | 375 | 0007 |          | 
+     |      | 525 | 0010 |          | 
+(16 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM uplt1 WHERE uplt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uplt2 WHERE uplt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM uplt1_e WHERE uplt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+  a  |  c   |  b  |  c   | ?column? |   c   
+-----+------+-----+------+----------+-------
+   0 | 0000 |   0 | 0000 |        0 | A0000
+  50 | 0001 |     |      |      100 | A0001
+ 100 | 0002 |     |      |      200 | A0002
+ 150 | 0003 | 150 | 0003 |      300 | A0003
+ 200 | 0004 |     |      |      400 | A0004
+ 250 | 0005 |     |      |      500 | A0005
+ 300 | 0006 | 300 | 0006 |      600 | A0006
+ 350 | 0007 |     |      |      700 | A0007
+ 400 | 0008 |     |      |      800 | A0008
+ 450 | 0009 | 450 | 0009 |      900 | A0009
+ 500 | 0010 |     |      |     1000 | A0010
+ 550 | 0011 |     |      |     1100 | A0011
+     |      |  75 | 0001 |          | 
+     |      | 225 | 0004 |          | 
+     |      | 375 | 0007 |          | 
+     |      | 525 | 0010 |          | 
+(16 rows)
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1, plt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c
+   Sort Key: t1.a
+   ->  Append
+         ->  Nested Loop Semi Join
+               Output: t1.a, t1.b, t1.c
+               Join Filter: (t1.c = t1_3.c)
+               ->  Seq Scan on public.plt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_3.c, t2.c
+                     Hash Cond: (t1_3.c = ltrim(t2.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p1 t1_3
+                           Output: t1_3.c
+                     ->  Hash
+                           Output: t2.c
+                           ->  Seq Scan on public.plt1_e_p1 t2
+                                 Output: t2.c
+         ->  Nested Loop Semi Join
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Join Filter: (t1_1.c = t1_4.c)
+               ->  Seq Scan on public.plt1_p2 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_4.c, t2_1.c
+                     Hash Cond: (t1_4.c = ltrim(t2_1.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p2 t1_4
+                           Output: t1_4.c
+                     ->  Hash
+                           Output: t2_1.c
+                           ->  Seq Scan on public.plt1_e_p2 t2_1
+                                 Output: t2_1.c
+         ->  Nested Loop Semi Join
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Join Filter: (t1_2.c = t1_5.c)
+               ->  Seq Scan on public.plt1_p3 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_5.c, t2_2.c
+                     Hash Cond: (t1_5.c = ltrim(t2_2.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p3 t1_5
+                           Output: t1_5.c
+                     ->  Hash
+                           Output: t2_2.c
+                           ->  Seq Scan on public.plt1_e_p3 t2_2
+                                 Output: t2_2.c
+(49 rows)
+
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1, plt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+  50 |  50 | 0001
+ 100 | 100 | 0002
+ 150 | 150 | 0003
+ 200 | 200 | 0004
+ 250 | 250 | 0005
+ 300 | 300 | 0006
+ 350 | 350 | 0007
+ 400 | 400 | 0008
+ 450 | 450 | 0009
+ 500 | 500 | 0010
+ 550 | 550 | 0011
+(12 rows)
+
+SELECT t1.* FROM uplt1 t1 WHERE t1.c IN (SELECT t1.c FROM uplt2 t1, uplt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+  50 |  50 | 0001
+ 100 | 100 | 0002
+ 150 | 150 | 0003
+ 200 | 200 | 0004
+ 250 | 250 | 0005
+ 300 | 300 | 0006
+ 350 | 350 | 0007
+ 400 | 400 | 0008
+ 450 | 450 | 0009
+ 500 | 500 | 0010
+ 550 | 550 | 0011
+(12 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM plt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+                                   QUERY PLAN                                   
+--------------------------------------------------------------------------------
+ Sort
+   Output: t1.a, t1.b, t1.c
+   Sort Key: t1.a
+   ->  Append
+         ->  Nested Loop Semi Join
+               Output: t1.a, t1.b, t1.c
+               Join Filter: (t1.c = t1_3.c)
+               ->  Seq Scan on public.plt1_p1 t1
+                     Output: t1.a, t1.b, t1.c
+                     Filter: ((t1.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_3.c, t1_6.c
+                     Hash Cond: (t1_3.c = ltrim(t1_6.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p1 t1_3
+                           Output: t1_3.c
+                     ->  Hash
+                           Output: t1_6.c
+                           ->  HashAggregate
+                                 Output: t1_6.c
+                                 Group Key: ltrim(t1_6.c, 'A'::text)
+                                 ->  Seq Scan on public.plt1_e_p1 t1_6
+                                       Output: t1_6.c, ltrim(t1_6.c, 'A'::text)
+                                       Filter: ((t1_6.a % 25) = 0)
+         ->  Nested Loop Semi Join
+               Output: t1_1.a, t1_1.b, t1_1.c
+               Join Filter: (t1_1.c = t1_4.c)
+               ->  Seq Scan on public.plt1_p2 t1_1
+                     Output: t1_1.a, t1_1.b, t1_1.c
+                     Filter: ((t1_1.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_4.c, t1_7.c
+                     Hash Cond: (t1_4.c = ltrim(t1_7.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p2 t1_4
+                           Output: t1_4.c
+                     ->  Hash
+                           Output: t1_7.c
+                           ->  HashAggregate
+                                 Output: t1_7.c
+                                 Group Key: ltrim(t1_7.c, 'A'::text)
+                                 ->  Seq Scan on public.plt1_e_p2 t1_7
+                                       Output: t1_7.c, ltrim(t1_7.c, 'A'::text)
+                                       Filter: ((t1_7.a % 25) = 0)
+         ->  Nested Loop Semi Join
+               Output: t1_2.a, t1_2.b, t1_2.c
+               Join Filter: (t1_2.c = t1_5.c)
+               ->  Seq Scan on public.plt1_p3 t1_2
+                     Output: t1_2.a, t1_2.b, t1_2.c
+                     Filter: ((t1_2.a % 25) = 0)
+               ->  Hash Join
+                     Output: t1_5.c, t1_8.c
+                     Hash Cond: (t1_5.c = ltrim(t1_8.c, 'A'::text))
+                     ->  Seq Scan on public.plt2_p3 t1_5
+                           Output: t1_5.c
+                     ->  Hash
+                           Output: t1_8.c
+                           ->  HashAggregate
+                                 Output: t1_8.c
+                                 Group Key: ltrim(t1_8.c, 'A'::text)
+                                 ->  Seq Scan on public.plt1_e_p3 t1_8
+                                       Output: t1_8.c, ltrim(t1_8.c, 'A'::text)
+                                       Filter: ((t1_8.a % 25) = 0)
+(61 rows)
+
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM plt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+  50 |  50 | 0001
+ 100 | 100 | 0002
+ 150 | 150 | 0003
+ 200 | 200 | 0004
+ 250 | 250 | 0005
+ 300 | 300 | 0006
+ 350 | 350 | 0007
+ 400 | 400 | 0008
+ 450 | 450 | 0009
+ 500 | 500 | 0010
+ 550 | 550 | 0011
+(12 rows)
+
+SELECT t1.* FROM uplt1 t1 WHERE t1.c IN (SELECT t1.c FROM uplt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM uplt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+  a  |  b  |  c   
+-----+-----+------
+   0 |   0 | 0000
+  50 |  50 | 0001
+ 100 | 100 | 0002
+ 150 | 150 | 0003
+ 200 | 200 | 0004
+ 250 | 250 | 0005
+ 300 | 300 | 0006
+ 350 | 350 | 0007
+ 400 | 400 | 0008
+ 450 | 450 | 0009
+ 500 | 500 | 0010
+ 550 | 550 | 0011
+(12 rows)
+
+--
+-- negative testcases
+--
+-- joins where one of the relations is proven empty
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a = 1 AND t1.a = 2;
+            QUERY PLAN            
+----------------------------------
+ Result
+   Output: t1.a, t1.c, t2.b, t2.c
+   One-Time Filter: false
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
+              QUERY PLAN              
+--------------------------------------
+ Result
+   Output: prt1.a, prt1.c, t2.b, t2.c
+   One-Time Filter: false
+(3 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                     
+---------------------------------------------------
+ Sort
+   Output: a, c, t2.b, t2.c
+   Sort Key: a, t2.b
+   ->  Hash Left Join
+         Output: a, c, t2.b, t2.c
+         Hash Cond: (t2.b = a)
+         ->  Append
+               ->  Seq Scan on public.prt2 t2
+                     Output: t2.b, t2.c
+                     Filter: ((t2.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
+                     Filter: ((t2_1.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
+                     Filter: ((t2_2.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p3 t2_3
+                     Output: t2_3.b, t2_3.c
+                     Filter: ((t2_3.a % 25) = 0)
+         ->  Hash
+               Output: a, c
+               ->  Result
+                     Output: a, c
+                     One-Time Filter: false
+(24 rows)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                     
+---------------------------------------------------
+ Sort
+   Output: a, c, t2.b, t2.c
+   Sort Key: a, t2.b
+   ->  Hash Left Join
+         Output: a, c, t2.b, t2.c
+         Hash Cond: (t2.b = a)
+         ->  Append
+               ->  Seq Scan on public.prt2 t2
+                     Output: t2.b, t2.c
+                     Filter: ((t2.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p1 t2_1
+                     Output: t2_1.b, t2_1.c
+                     Filter: ((t2_1.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p2 t2_2
+                     Output: t2_2.b, t2_2.c
+                     Filter: ((t2_2.a % 25) = 0)
+               ->  Seq Scan on public.prt2_p3 t2_3
+                     Output: t2_3.b, t2_3.c
+                     Filter: ((t2_3.a % 25) = 0)
+         ->  Hash
+               Output: a, c
+               ->  Result
+                     Output: a, c
+                     One-Time Filter: false
+(24 rows)
+
+CREATE TABLE prt1_n (a int, b int, c varchar) PARTITION BY RANGE(c);
+CREATE TABLE prt1_n_p1 PARTITION OF prt1_n FOR VALUES FROM ('0000') TO ('0250');
+CREATE TABLE prt1_n_p2 PARTITION OF prt1_n FOR VALUES FROM ('0250') TO ('0500');
+INSERT INTO prt1_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 499, 2) i;
+ANALYZE prt1_n;
+ANALYZE prt1_n_p1;
+ANALYZE prt1_n_p2;
+CREATE TABLE prt2_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt2_n_p1 PARTITION OF prt2_n FOR VALUES IN ('0000', '0003', '0004', '0010', '0006', '0007');
+CREATE TABLE prt2_n_p2 PARTITION OF prt2_n FOR VALUES IN ('0001', '0005', '0002', '0009', '0008', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt2_n;
+ANALYZE prt2_n_p1;
+ANALYZE prt2_n_p2;
+CREATE TABLE prt3_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt3_n_p1 PARTITION OF prt3_n FOR VALUES IN ('0000', '0004', '0006', '0007');
+CREATE TABLE prt3_n_p2 PARTITION OF prt3_n FOR VALUES IN ('0001', '0002', '0008', '0010');
+CREATE TABLE prt3_n_p3 PARTITION OF prt3_n FOR VALUES IN ('0003', '0005', '0009', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt3_n;
+ANALYZE prt3_n_p1;
+ANALYZE prt3_n_p2;
+ANALYZE prt3_n_p3;
+CREATE TABLE prt4_n (a int, b int, c text) PARTITION BY RANGE(a);
+CREATE TABLE prt4_n_p1 PARTITION OF prt4_n FOR VALUES FROM (0) TO (300);
+CREATE TABLE prt4_n_p2 PARTITION OF prt4_n FOR VALUES FROM (300) TO (500);
+CREATE TABLE prt4_n_p3 PARTITION OF prt4_n FOR VALUES FROM (500) TO (600);
+INSERT INTO prt4_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt4_n;
+ANALYZE prt4_n_p1;
+ANALYZE prt4_n_p2;
+ANALYZE prt4_n_p3;
+-- partition-wise join can not be applied if the partition ranges differ
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Join
+   Hash Cond: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on prt1 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p3 t1_2
+         ->  Seq Scan on prt1_p2 t1_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt4_n t2
+               ->  Seq Scan on prt4_n_p1 t2_1
+               ->  Seq Scan on prt4_n_p2 t2_2
+               ->  Seq Scan on prt4_n_p3 t2_3
+(13 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 FULL JOIN prt4_n t2 ON t1.a = t2.a;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Full Join
+   Hash Cond: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on prt1 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p3 t1_2
+         ->  Seq Scan on prt1_p2 t1_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt4_n t2
+               ->  Seq Scan on prt4_n_p1 t2_1
+               ->  Seq Scan on prt4_n_p2 t2_2
+               ->  Seq Scan on prt4_n_p3 t2_3
+(13 rows)
+
+-- partition-wise join can not be applied if there are no equi-join conditions
+-- between partition keys
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON (t1.a < t2.b);
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Nested Loop Left Join
+   ->  Append
+         ->  Seq Scan on prt1 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p3 t1_2
+         ->  Seq Scan on prt1_p2 t1_3
+   ->  Append
+         ->  Seq Scan on prt2 t2
+               Filter: (t1.a < b)
+         ->  Index Scan using iprt2_p1_b on prt2_p1 t2_1
+               Index Cond: (t1.a < b)
+         ->  Index Scan using iprt2_p2_b on prt2_p2 t2_2
+               Index Cond: (t1.a < b)
+         ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+               Index Cond: (t1.a < b)
+(15 rows)
+
+-- equi-join with join condition on partial keys does not qualify for
+-- partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1, prt2_m t2 WHERE t1.a = (t2.b + t2.a)/2 AND t1.a % 25 = 0;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Join
+   Hash Cond: (((t2.b + t2.a) / 2) = t1.a)
+   ->  Append
+         ->  Seq Scan on prt2_m t2
+         ->  Seq Scan on prt2_m_p1 t2_1
+         ->  Seq Scan on prt2_m_p2 t2_2
+         ->  Seq Scan on prt2_m_p3 t2_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_m t1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p1 t1_1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p2 t1_2
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p3 t1_3
+                     Filter: ((a % 25) = 0)
+(17 rows)
+
+-- equi-join between out-of-order partition key columns does not qualify for
+-- partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.a = t2.b WHERE t1.a % 25 = 0;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Right Join
+   Hash Cond: (t2.b = t1.a)
+   ->  Append
+         ->  Seq Scan on prt2_m t2
+         ->  Seq Scan on prt2_m_p1 t2_1
+         ->  Seq Scan on prt2_m_p2 t2_2
+         ->  Seq Scan on prt2_m_p3 t2_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_m t1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p1 t1_1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p2 t1_2
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p3 t1_3
+                     Filter: ((a % 25) = 0)
+(17 rows)
+
+-- equi-join between non-key columns does not qualify for partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.c = t2.c WHERE t1.a % 25 = 0;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Right Join
+   Hash Cond: ((t2.c)::text = (t1.c)::text)
+   ->  Append
+         ->  Seq Scan on prt2_m t2
+         ->  Seq Scan on prt2_m_p1 t2_1
+         ->  Seq Scan on prt2_m_p2 t2_2
+         ->  Seq Scan on prt2_m_p3 t2_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_m t1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p1 t1_1
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p2 t1_2
+                     Filter: ((a % 25) = 0)
+               ->  Seq Scan on prt1_m_p3 t1_3
+                     Filter: ((a % 25) = 0)
+(17 rows)
+
+-- partition-wise join can not be applied for a join between list and range
+-- partitioned table
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1, prt2_n t2 WHERE t1.c = t2.c;
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Join
+   Hash Cond: (t2.c = (t1.c)::text)
+   ->  Append
+         ->  Seq Scan on prt2_n t2
+         ->  Seq Scan on prt2_n_p1 t2_1
+         ->  Seq Scan on prt2_n_p2 t2_2
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_n t1
+               ->  Seq Scan on prt1_n_p1 t1_1
+               ->  Seq Scan on prt1_n_p2 t1_2
+(11 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 LEFT JOIN prt2_n t2 ON (t1.c = t2.c);
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Right Join
+   Hash Cond: (t2.c = (t1.c)::text)
+   ->  Append
+         ->  Seq Scan on prt2_n t2
+         ->  Seq Scan on prt2_n_p1 t2_1
+         ->  Seq Scan on prt2_n_p2 t2_2
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_n t1
+               ->  Seq Scan on prt1_n_p1 t1_1
+               ->  Seq Scan on prt1_n_p2 t1_2
+(11 rows)
+
+-- partition-wise join can not be applied between tables with different
+-- partition lists
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 RIGHT JOIN prt1 t2 ON (t1.c = t2.c);
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Left Join
+   Hash Cond: ((t2.c)::text = (t1.c)::text)
+   ->  Append
+         ->  Seq Scan on prt1 t2
+         ->  Seq Scan on prt1_p1 t2_1
+         ->  Seq Scan on prt1_p3 t2_2
+         ->  Seq Scan on prt1_p2 t2_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_n t1
+               ->  Seq Scan on prt1_n_p1 t1_1
+               ->  Seq Scan on prt1_n_p2 t1_2
+(12 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c);
+                  QUERY PLAN                  
+----------------------------------------------
+ Hash Full Join
+   Hash Cond: ((t2.c)::text = (t1.c)::text)
+   ->  Append
+         ->  Seq Scan on prt1 t2
+         ->  Seq Scan on prt1_p1 t2_1
+         ->  Seq Scan on prt1_p3 t2_2
+         ->  Seq Scan on prt1_p2 t2_3
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt1_n t1
+               ->  Seq Scan on prt1_n_p1 t1_1
+               ->  Seq Scan on prt1_n_p2 t1_2
+(12 rows)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index edeb2d6..ac38f50 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
+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
 # ----------
 # 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 27a46d7..1bf98a4 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -172,3 +172,4 @@ test: with
 test: xml
 test: event_trigger
 test: stats
+test: partition_join
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
new file mode 100644
index 0000000..0322f1e
--- /dev/null
+++ b/src/test/regress/sql/partition_join.sql
@@ -0,0 +1,515 @@
+--
+-- PARTITION_JOIN
+-- Test partition-wise join between partitioned tables
+--
+
+--
+-- partitioned by a single column
+--
+CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p1 PARTITION OF prt1 FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_p3 PARTITION OF prt1 FOR VALUES FROM (500) TO (600);
+CREATE TABLE prt1_p2 PARTITION OF prt1 FOR VALUES FROM (250) TO (500);
+INSERT INTO prt1 SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1;
+ANALYZE prt1_p1;
+ANALYZE prt1_p2;
+ANALYZE prt1_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1 AS SELECT * FROM prt1;
+
+CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p1 PARTITION OF prt2 FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_p2 PARTITION OF prt2 FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_p3 PARTITION OF prt2 FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2 SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+ANALYZE prt2;
+ANALYZE prt2_p1;
+ANALYZE prt2_p2;
+ANALYZE prt2_p3;
+CREATE TABLE uprt2 AS SELECT * FROM prt2;
+
+-- inner join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1 t1, uprt2 t2 WHERE t1.a = t2.b AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- left outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- right outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+
+-- full outer join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+
+-- Cases with non-nullable expressions in subquery results;
+-- make sure these go to null as expected
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.b OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t1.phv, t2.b, t2.c, t2.phv FROM (SELECT 25 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 50 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
+
+-- Join with pruned partitions from joining relations
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1 t1, uprt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM uprt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450) t1 RIGHT JOIN (SELECT * FROM uprt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1 WHERE a < 450 AND a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 WHERE b > 250 AND b % 25 = 0) t2 ON t1.a = t2.b ORDER BY t1.a, t2.b;
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b % 25 = 0) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+-- lateral reference
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+
+--
+-- partitioned by expression
+--
+CREATE TABLE prt1_e (a int, b int, c varchar) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p1 PARTITION OF prt1_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_e_p2 PARTITION OF prt1_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt1_e_p3 PARTITION OF prt1_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt1_e SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_e;
+ANALYZE prt1_e_p1;
+ANALYZE prt1_e_p2;
+ANALYZE prt1_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_e AS SELECT * FROM prt1_e;
+
+CREATE TABLE prt2_e (a int, b int, c varchar) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p1 PARTITION OF prt2_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_e_p2 PARTITION OF prt2_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_e_p3 PARTITION OF prt2_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2_e SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_e;
+ANALYZE prt2_e_p1;
+ANALYZE prt2_e_p2;
+ANALYZE prt2_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_e AS SELECT * FROM prt2_e;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_e t1, uprt2_e t2 WHERE (t1.a + t1.b)/2 = (t2.b + t2.a)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1 LEFT JOIN prt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1 LEFT JOIN prt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_e t1 LEFT JOIN uprt2_e t2 ON (t1.a + t1.b)/2 = (t2.b + t2.a)/2 WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+--
+-- N-way join
+--
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM uprt1 t1, uprt2 t2, uprt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) LEFT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) LEFT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) LEFT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT * FROM uprt1_e WHERE uprt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+-- Cases with non-nullable expressions in subquery results;
+-- make sure these go to null as expected
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM uprt1 WHERE uprt1.a % 25 = 0) t1 FULL JOIN (SELECT 75 phv, * FROM uprt2 WHERE uprt2.b % 25 = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM uprt1_e WHERE uprt1_e.a % 25 = 0) t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t1.a = t1.phv OR t2.b = t2.phv OR (t3.a + t3.b)/2 = t3.phv ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1, uprt1_e t2 WHERE t1.b % 25 = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+-- test merge joins with and without using indexes
+SET enable_hashjoin TO off;
+SET enable_nestloop TO off;
+
+CREATE INDEX iprt1_p1_a on prt1_p1(a);
+CREATE INDEX iprt1_p2_a on prt1_p2(a);
+CREATE INDEX iprt1_p3_a on prt1_p3(a);
+CREATE INDEX iprt2_p1_b on prt2_p1(b);
+CREATE INDEX iprt2_p2_b on prt2_p2(b);
+CREATE INDEX iprt2_p3_b on prt2_p3(b);
+CREATE INDEX iprt1_e_p1_ab2 on prt1_e_p1(((a+b)/2));
+CREATE INDEX iprt1_e_p2_ab2 on prt1_e_p2(((a+b)/2));
+CREATE INDEX iprt1_e_p3_ab2 on prt1_e_p3(((a+b)/2));
+
+ANALYZE prt1;
+ANALYZE prt1_p1;
+ANALYZE prt1_p2;
+ANALYZE prt1_p3;
+ANALYZE prt2;
+ANALYZE prt2_p1;
+ANALYZE prt2_p2;
+ANALYZE prt2_p3;
+ANALYZE prt1_e;
+ANALYZE prt1_e_p1;
+ANALYZE prt1_e_p2;
+ANALYZE prt1_e_p3;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+SET enable_seqscan TO off;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 RIGHT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t2.b = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uprt1 t1 WHERE t1.a IN (SELECT t1.b FROM uprt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM uprt1_e t1 WHERE t1.a %25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b) RIGHT JOIN prt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uprt1 t1 LEFT JOIN uprt2 t2 ON t1.a = t2.b) RIGHT JOIN uprt1_e t3 ON (t1.a = (t3.a + t3.b)/2) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+-- lateral references and parameterized paths
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.a = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM prt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+SELECT * FROM uprt1 t1 LEFT JOIN LATERAL
+			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.a) FROM uprt1 t2 JOIN uprt2 t3 ON (t2.a = t3.b)) ss
+			  ON t1.b = ss.t2a WHERE t1.a % 25 = 0 ORDER BY t1.a;
+
+RESET enable_hashjoin;
+RESET enable_nestloop;
+RESET enable_seqscan;
+
+--
+-- partitioned by multiple columns
+--
+CREATE TABLE prt1_m (a int, b int, c varchar) PARTITION BY RANGE(a, ((a + b)/2));
+CREATE TABLE prt1_m_p1 PARTITION OF prt1_m FOR VALUES FROM (0, 0) TO (250, 250);
+CREATE TABLE prt1_m_p2 PARTITION OF prt1_m FOR VALUES FROM (250, 250) TO (500, 500);
+CREATE TABLE prt1_m_p3 PARTITION OF prt1_m FOR VALUES FROM (500, 500) TO (600, 600);
+INSERT INTO prt1_m SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_m;
+ANALYZE prt1_m_p1;
+ANALYZE prt1_m_p2;
+ANALYZE prt1_m_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt1_m AS SELECT * FROM prt1_m;
+
+CREATE TABLE prt2_m (a int, b int, c varchar) PARTITION BY RANGE(((b + a)/2), b);
+CREATE TABLE prt2_m_p1 PARTITION OF prt2_m FOR VALUES FROM (0, 0) TO (250, 250);
+CREATE TABLE prt2_m_p2 PARTITION OF prt2_m FOR VALUES FROM (250, 250) TO (500, 500);
+CREATE TABLE prt2_m_p3 PARTITION OF prt2_m FOR VALUES FROM (500, 500) TO (600, 600);
+INSERT INTO prt2_m SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_m;
+ANALYZE prt2_m_p1;
+ANALYZE prt2_m_p2;
+ANALYZE prt2_m_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uprt2_m AS SELECT * FROM prt2_m;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 RIGHT JOIN prt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 RIGHT JOIN prt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM uprt1_m t1 RIGHT JOIN uprt2_m t2 ON t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2 WHERE t2.b % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.a % 25 = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM uprt1_m t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uprt2_m t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = (t2.b + t2.a)/2 AND t2.b = (t1.a + t1.b)/2) ORDER BY t1.a, t2.b;
+
+--
+-- tests for list partitioned tables.
+--
+CREATE TABLE plt1 (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE plt1;
+ANALYZE plt1_p1;
+ANALYZE plt1_p2;
+ANALYZE plt1_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt1 AS SELECT * FROM plt1;
+
+CREATE TABLE plt2 (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE plt2;
+ANALYZE plt2_p1;
+ANALYZE plt2_p2;
+ANALYZE plt2_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt2 AS SELECT * FROM plt2;
+
+--
+-- list partitioned by expression
+--
+CREATE TABLE plt1_e (a int, b int, c text) PARTITION BY LIST(ltrim(c, 'A'));
+CREATE TABLE plt1_e_p1 PARTITION OF plt1_e FOR VALUES IN ('0000', '0003', '0004', '0010');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0001', '0005', '0002', '0009');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0006', '0007', '0008', '0011');
+INSERT INTO plt1_e SELECT i, i, 'A' || to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE plt1_e;
+ANALYZE plt1_e_p1;
+ANALYZE plt1_e_p2;
+ANALYZE plt1_e_p3;
+-- TODO: This table is created only for testing the results. Remove once
+-- results are tested.
+CREATE TABLE uplt1_e AS SELECT * FROM plt1_e;
+
+--
+-- N-way join
+--
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, plt2 t2, plt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM uplt1 t1, uplt2 t2, uplt1_e t3 WHERE t1.c = t2.c AND ltrim(t3.c, 'A') = t1.c GROUP BY t1.c, t2.c, t3.c ORDER BY t1.c, t2.c, t3.c;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN uplt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) LEFT JOIN uplt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t1.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 LEFT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 LEFT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN uplt1_e t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 RIGHT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (plt1 t1 RIGHT JOIN plt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN plt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (uplt1 t1 RIGHT JOIN uplt2 t2 ON t1.a = t2.b AND t1.c = t2.c) RIGHT JOIN uplt1_e t3 ON (t2.b = t3.a AND t2.c = ltrim(t3.c, 'A')) WHERE t3.a % 25 = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM plt1 WHERE plt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM plt2 WHERE plt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM plt1_e WHERE plt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM plt1 WHERE plt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM plt2 WHERE plt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM plt1_e WHERE plt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM ((SELECT * FROM uplt1 WHERE uplt1.a % 25 = 0) t1 FULL JOIN (SELECT * FROM uplt2 WHERE uplt2.b % 25 = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c)) FULL JOIN (SELECT * FROM uplt1_e WHERE uplt1_e.a % 25 = 0) t3 ON (t1.a = t3.a AND ltrim(t3.c, 'A') = t1.c) ORDER BY t1.a, t2.b, t3.a + t3.b;
+
+-- Semi-join
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1, plt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1, plt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uplt1 t1 WHERE t1.c IN (SELECT t1.c FROM uplt2 t1, uplt1_e t2 WHERE t1.c = ltrim(t2.c, 'A')) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM plt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM plt1 t1 WHERE t1.c IN (SELECT t1.c FROM plt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM plt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+SELECT t1.* FROM uplt1 t1 WHERE t1.c IN (SELECT t1.c FROM uplt2 t1 WHERE t1.c IN (SELECT ltrim(t1.c, 'A') FROM uplt1_e t1 WHERE t1.a % 25 = 0)) AND t1.a % 25 = 0 ORDER BY t1.a;
+
+--
+-- negative testcases
+--
+
+-- joins where one of the relations is proven empty
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a = 1 AND t1.a = 2;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a % 25 = 0 ORDER BY t1.a, t2.b;
+
+CREATE TABLE prt1_n (a int, b int, c varchar) PARTITION BY RANGE(c);
+CREATE TABLE prt1_n_p1 PARTITION OF prt1_n FOR VALUES FROM ('0000') TO ('0250');
+CREATE TABLE prt1_n_p2 PARTITION OF prt1_n FOR VALUES FROM ('0250') TO ('0500');
+INSERT INTO prt1_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 499, 2) i;
+ANALYZE prt1_n;
+ANALYZE prt1_n_p1;
+ANALYZE prt1_n_p2;
+
+CREATE TABLE prt2_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt2_n_p1 PARTITION OF prt2_n FOR VALUES IN ('0000', '0003', '0004', '0010', '0006', '0007');
+CREATE TABLE prt2_n_p2 PARTITION OF prt2_n FOR VALUES IN ('0001', '0005', '0002', '0009', '0008', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt2_n;
+ANALYZE prt2_n_p1;
+ANALYZE prt2_n_p2;
+
+CREATE TABLE prt3_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt3_n_p1 PARTITION OF prt3_n FOR VALUES IN ('0000', '0004', '0006', '0007');
+CREATE TABLE prt3_n_p2 PARTITION OF prt3_n FOR VALUES IN ('0001', '0002', '0008', '0010');
+CREATE TABLE prt3_n_p3 PARTITION OF prt3_n FOR VALUES IN ('0003', '0005', '0009', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt3_n;
+ANALYZE prt3_n_p1;
+ANALYZE prt3_n_p2;
+ANALYZE prt3_n_p3;
+
+CREATE TABLE prt4_n (a int, b int, c text) PARTITION BY RANGE(a);
+CREATE TABLE prt4_n_p1 PARTITION OF prt4_n FOR VALUES FROM (0) TO (300);
+CREATE TABLE prt4_n_p2 PARTITION OF prt4_n FOR VALUES FROM (300) TO (500);
+CREATE TABLE prt4_n_p3 PARTITION OF prt4_n FOR VALUES FROM (500) TO (600);
+INSERT INTO prt4_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt4_n;
+ANALYZE prt4_n_p1;
+ANALYZE prt4_n_p2;
+ANALYZE prt4_n_p3;
+
+-- partition-wise join can not be applied if the partition ranges differ
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 FULL JOIN prt4_n t2 ON t1.a = t2.a;
+
+-- partition-wise join can not be applied if there are no equi-join conditions
+-- between partition keys
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON (t1.a < t2.b);
+
+-- equi-join with join condition on partial keys does not qualify for
+-- partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1, prt2_m t2 WHERE t1.a = (t2.b + t2.a)/2 AND t1.a % 25 = 0;
+
+-- equi-join between out-of-order partition key columns does not qualify for
+-- partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.a = t2.b WHERE t1.a % 25 = 0;
+
+-- equi-join between non-key columns does not qualify for partition-wise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.c = t2.c WHERE t1.a % 25 = 0;
+
+-- partition-wise join can not be applied for a join between list and range
+-- partitioned table
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1, prt2_n t2 WHERE t1.c = t2.c;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 LEFT JOIN prt2_n t2 ON (t1.c = t2.c);
+
+-- partition-wise join can not be applied between tables with different
+-- partition lists
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 RIGHT JOIN prt1 t2 ON (t1.c = t2.c);
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c);
-- 
1.7.9.5

