agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH 3/3] Tests for 0:1, 1:1 and 1:0 partition matching
6+ messages / 4 participants
[nested] [flat]

* [PATCH 3/3] Tests for 0:1, 1:1 and 1:0 partition matching
@ 2019-01-22 12:28 Etsuro Fujita <[email protected]>
  0 siblings, 0 replies; 6+ messages in thread

From: Etsuro Fujita @ 2019-01-22 12:28 UTC (permalink / raw)

Rajkumar Raghuvanshi and Ashutosh Bapat.
---
 src/test/regress/expected/partition_join.out | 4131 +++++++++++++++---
 src/test/regress/sql/partition_join.sql      |  427 +-
 2 files changed, 3855 insertions(+), 703 deletions(-)

diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index c55de5d476..f19611c853 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -8,59 +8,86 @@ SET enable_partitionwise_join to true;
 -- partitioned by a single column
 --
 CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p0 PARTITION OF prt1 FOR VALUES FROM (MINVALUE) TO (0);
 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 % 25, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 2 = 0;
+CREATE TABLE prt1_p4 PARTITION OF prt1 FOR VALUES FROM (600) TO (800);
+INSERT INTO prt1 SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 2 = 0;
+CREATE INDEX iprt1_p0_a on prt1_p0(a);
 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 iprt1_p4_a on prt1_p4(a);
 ANALYZE prt1;
+-- prt2 have missing starting MINVALUE to -250 range and
+-- extra bounds from 800 to MAXVALUE
 CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p0 PARTITION OF prt2 FOR VALUES FROM (-250) TO (0);
 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 % 25, i, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 3 = 0;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (MAXVALUE);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 3 = 0;
+CREATE INDEX iprt2_p0_b on prt2_p0(b);
 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 iprt2_p4_b on prt2_p4(b);
 ANALYZE prt2;
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
 -- inner join
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-                    QUERY PLAN                    
---------------------------------------------------
+                          QUERY PLAN                           
+---------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Hash Join
                Hash Cond: (t2.b = t1.a)
-               ->  Seq Scan on prt2_p1 t2
+               ->  Seq Scan on prt2_p0 t2
                ->  Hash
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
          ->  Hash Join
                Hash Cond: (t2_1.b = t1_1.a)
-               ->  Seq Scan on prt2_p2 t2_1
+               ->  Seq Scan on prt2_p1 t2_1
                ->  Hash
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
          ->  Hash Join
                Hash Cond: (t2_2.b = t1_2.a)
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p2 t2_2
                ->  Hash
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(21 rows)
+         ->  Nested Loop
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 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)
+  a   |   c   |  b   |   c   
+------+-------+------+-------
+ -150 | -0150 | -150 | -0150
+    0 | 0000  |    0 | 0000
+  150 | 0150  |  150 | 0150
+  300 | 0300  |  300 | 0300
+  450 | 0450  |  450 | 0450
+  600 | 0600  |  600 | 0600
+  750 | 0750  |  750 | 0750
+(7 rows)
 
 -- left outer join, with whole-row reference; partitionwise join does not apply
 EXPLAIN (COSTS OFF)
@@ -72,35 +99,50 @@ SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER
    ->  Hash Right Join
          Hash Cond: (t2.b = t1.a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
          ->  Hash
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(16 rows)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(22 rows)
 
 SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
-      t1      |      t2      
---------------+--------------
- (0,0,0000)   | (0,0,0000)
- (50,0,0050)  | 
- (100,0,0100) | 
- (150,0,0150) | (0,150,0150)
- (200,0,0200) | 
- (250,0,0250) | 
- (300,0,0300) | (0,300,0300)
- (350,0,0350) | 
- (400,0,0400) | 
- (450,0,0450) | (0,450,0450)
- (500,0,0500) | 
- (550,0,0550) | 
-(12 rows)
+       t1       |       t2       
+----------------+----------------
+ (-250,0,-0250) | 
+ (-200,0,-0200) | 
+ (-150,0,-0150) | (0,-150,-0150)
+ (-100,0,-0100) | 
+ (-50,0,-0050)  | 
+ (0,0,0000)     | (0,0,0000)
+ (50,0,0050)    | 
+ (100,0,0100)   | 
+ (150,0,0150)   | (0,150,0150)
+ (200,0,0200)   | 
+ (250,0,0250)   | 
+ (300,0,0300)   | (0,300,0300)
+ (350,0,0350)   | 
+ (400,0,0400)   | 
+ (450,0,0450)   | (0,450,0450)
+ (500,0,0500)   | 
+ (550,0,0550)   | 
+ (600,0,0600)   | (0,600,0600)
+ (650,0,0650)   | 
+ (700,0,0700)   | 
+ (750,0,0750)   | (0,750,0750)
+(21 rows)
 
 -- right outer join
 EXPLAIN (COSTS OFF)
@@ -112,35 +154,53 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHE
    ->  Append
          ->  Hash Right Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
                            Filter: (a = 0)
          ->  Hash Right Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+                           Filter: (a = 0)
+         ->  Hash Right Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
                            Filter: (a = 0)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
                      Filter: (a = 0)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
-                     Index Cond: (a = t2_2.b)
-(20 rows)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+(32 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 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)
+  a   |   c   |  b   |   c   
+------+-------+------+-------
+ -150 | -0150 | -150 | -0150
+    0 | 0000  |    0 | 0000
+  150 | 0150  |  150 | 0150
+  300 | 0300  |  300 | 0300
+  450 | 0450  |  450 | 0450
+  600 | 0600  |  600 | 0600
+  750 | 0750  |  750 | 0750
+      |       | -225 | -0225
+      |       |  -75 | -0075
+      |       |   75 | 0075
+      |       |  225 | 0225
+      |       |  375 | 0375
+      |       |  525 | 0525
+      |       |  675 | 0675
+(14 rows)
 
 -- full outer join, with placeholder vars
 EXPLAIN (COSTS OFF)
@@ -148,8 +208,16 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0)
                             QUERY PLAN                            
 ------------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, prt2_p1.b
+   Sort Key: prt1_p0.a, prt2_p0.b
    ->  Append
+         ->  Hash Full Join
+               Hash Cond: (prt1_p0.a = prt2_p0.b)
+               Filter: (((50) = prt1_p0.a) OR ((75) = prt2_p0.b))
+               ->  Seq Scan on prt1_p0
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0
+                           Filter: (a = 0)
          ->  Hash Full Join
                Hash Cond: (prt1_p1.a = prt2_p1.b)
                Filter: (((50) = prt1_p1.a) OR ((75) = prt2_p1.b))
@@ -174,7 +242,15 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0)
                ->  Hash
                      ->  Seq Scan on prt2_p3
                            Filter: (a = 0)
-(27 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt1_p4.a = prt2_p4.b)
+               Filter: (((50) = prt1_p4.a) OR ((75) = prt2_p4.b))
+               ->  Seq Scan on prt1_p4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4
+                           Filter: (a = 0)
+(43 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b;
  a  |  c   | b  |  c   
@@ -211,8 +287,15 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO
                         QUERY PLAN                         
 -----------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Hash Left Join
+               Hash Cond: (prt1_p0.a = b)
+               ->  Seq Scan on prt1_p0
+                     Filter: ((a < 450) AND (b = 0))
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
          ->  Hash Left Join
                Hash Cond: (prt1_p1.a = b)
                ->  Seq Scan on prt1_p1
@@ -227,29 +310,42 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO
                ->  Hash
                      ->  Seq Scan on prt1_p2
                            Filter: ((a < 450) AND (b = 0))
-(17 rows)
+(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.b = 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)
+  a   |   c   |  b  |  c   
+------+-------+-----+------
+ -250 | -0250 |     | 
+ -200 | -0200 |     | 
+ -150 | -0150 |     | 
+ -100 | -0100 |     | 
+  -50 | -0050 |     | 
+    0 | 0000  |     | 
+   50 | 0050  |     | 
+  100 | 0100  |     | 
+  150 | 0150  |     | 
+  200 | 0200  |     | 
+  250 | 0250  |     | 
+  300 | 0300  | 300 | 0300
+  350 | 0350  |     | 
+  400 | 0400  |     | 
+(14 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 0 ORDER BY t1.a, t2.b;
                          QUERY PLAN                         
 ------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Hash Full Join
+               Hash Cond: (prt1_p0.a = b)
+               Filter: ((prt1_p0.b = 0) OR (a = 0))
+               ->  Seq Scan on prt1_p0
+                     Filter: (a < 450)
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
          ->  Hash Full Join
                Hash Cond: (prt1_p1.a = b)
                Filter: ((prt1_p1.b = 0) OR (a = 0))
@@ -274,64 +370,153 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO
                ->  Hash
                      ->  Result
                            One-Time Filter: false
-(27 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt2_p4.b = a)
+               Filter: ((b = 0) OR (prt2_p4.a = 0))
+               ->  Seq Scan on prt2_p4
+                     Filter: (b > 250)
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
+(43 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 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 |     | 
-     |      | 375 | 0375
-     |      | 450 | 0450
-     |      | 525 | 0525
-(12 rows)
+  a   |   c   |  b  |  c   
+------+-------+-----+------
+ -250 | -0250 |     | 
+ -200 | -0200 |     | 
+ -150 | -0150 |     | 
+ -100 | -0100 |     | 
+  -50 | -0050 |     | 
+    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
+      |       | 600 | 0600
+      |       | 675 | 0675
+      |       | 750 | 0750
+(20 rows)
 
 -- Semi-join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
-                    QUERY PLAN                    
---------------------------------------------------
+                          QUERY PLAN                           
+---------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Hash Semi Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
                            Filter: (a = 0)
          ->  Hash Semi Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
                            Filter: (a = 0)
-         ->  Nested Loop Semi Join
-               Join Filter: (t1_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t1_2
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
-               ->  Materialize
-                     ->  Seq Scan on prt2_p3 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
                            Filter: (a = 0)
-(24 rows)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t2_3.b
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+                     Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+(39 rows)
 
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b
+   ->  Append
+         ->  Hash Semi Join
+               Hash Cond: (t1.b = t2.a)
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t2
+                           Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_1.b = t2_1.a)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t2_1
+                           Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.b = t2_2.a)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t2_2
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: (t1_3.b = t2_3.a)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt1_p3 t2_3
+                     Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.b = t2_4.a)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t2_4
+                           Filter: (b = 0)
+(37 rows)
+
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+ a |  b   |   c   
+---+------+-------
+ 0 | -150 | -0150
+ 0 |    0 | 0000
+ 0 |  150 | 0150
+ 0 |  300 | 0300
+ 0 |  450 | 0450
+ 0 |  600 | 0600
+ 0 |  750 | 0750
+(7 rows)
 
 -- Anti-join with aggregates
 EXPLAIN (COSTS OFF)
@@ -342,27 +527,82 @@ SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS
    ->  Append
          ->  Hash Anti Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
          ->  Hash Anti Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
          ->  Hash Anti Join
                Hash Cond: (t1_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                ->  Hash
-                     ->  Seq Scan on prt2_p3 t2_2
-(17 rows)
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Hash Anti Join
+               Hash Cond: (t1_3.a = t2_3.b)
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on prt2_p3 t2_3
+         ->  Hash Anti Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(27 rows)
 
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
-  sum  |         avg          | sum  |         avg         
--------+----------------------+------+---------------------
- 60000 | 300.0000000000000000 | 2400 | 12.0000000000000000
+  sum  |         avg          | sum  |        avg         
+-------+----------------------+------+--------------------
+ 95550 | 273.0000000000000000 | 2200 | 6.2857142857142857
 (1 row)
 
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Append
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p0 t1
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
+               Index Cond: (a = t1.b)
+   ->  Hash Anti Join
+         Hash Cond: (t1_1.b = t2_1.a)
+         ->  Seq Scan on prt2_p1 t1_1
+               Filter: (a = 0)
+         ->  Hash
+               ->  Seq Scan on prt1_p1 t2_1
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p2 t1_2
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
+               Index Cond: (a = t1_2.b)
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p3 t1_3
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+               Index Cond: (a = t1_3.b)
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p4 t1_4
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+               Index Cond: (a = t1_4.b)
+(27 rows)
+
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+  b   |   c   
+------+-------
+ -225 | -0225
+  -75 | -0075
+   75 | 0075
+  225 | 0225
+  375 | 0375
+  525 | 0525
+  675 | 0675
+(7 rows)
+
 -- lateral reference
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
@@ -374,49 +614,74 @@ SELECT * FROM prt1 t1 LEFT JOIN LATERAL
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2
+                     ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
                            Index Cond: (a = t1.a)
-                     ->  Index Scan using iprt2_p1_b on prt2_p1 t3
+                     ->  Index Scan using iprt2_p0_b on prt2_p0 t3
                            Index Cond: (b = t2.a)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_1
+                     ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2_1
                            Index Cond: (a = t1_1.a)
-                     ->  Index Scan using iprt2_p2_b on prt2_p2 t3_1
+                     ->  Index Scan using iprt2_p1_b on prt2_p1 t3_1
                            Index Cond: (b = t2_1.a)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_2
+                     ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
                            Index Cond: (a = t1_2.a)
-                     ->  Index Scan using iprt2_p3_b on prt2_p3 t3_2
+                     ->  Index Scan using iprt2_p2_b on prt2_p2 t3_2
                            Index Cond: (b = t2_2.a)
-(27 rows)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Nested Loop
+                     ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+                           Index Cond: (a = t1_3.a)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t3_3
+                           Index Cond: (b = t2_3.a)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Nested Loop
+                     ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+                           Index Cond: (a = t1_4.a)
+                     ->  Index Scan using iprt2_p4_b on prt2_p4 t3_4
+                           Index Cond: (b = t2_4.a)
+(43 rows)
 
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
 			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
 			  ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   | t2a | t3a | least 
------+---+------+-----+-----+-------
-   0 | 0 | 0000 |   0 |   0 |     0
-  50 | 0 | 0050 |     |     |      
- 100 | 0 | 0100 |     |     |      
- 150 | 0 | 0150 | 150 |   0 |   150
- 200 | 0 | 0200 |     |     |      
- 250 | 0 | 0250 |     |     |      
- 300 | 0 | 0300 | 300 |   0 |   300
- 350 | 0 | 0350 |     |     |      
- 400 | 0 | 0400 |     |     |      
- 450 | 0 | 0450 | 450 |   0 |   450
- 500 | 0 | 0500 |     |     |      
- 550 | 0 | 0550 |     |     |      
-(12 rows)
+  a   | b |   c   | t2a  | t3a | least 
+------+---+-------+------+-----+-------
+ -250 | 0 | -0250 |      |     |      
+ -200 | 0 | -0200 |      |     |      
+ -150 | 0 | -0150 | -150 |   0 |  -150
+ -100 | 0 | -0100 |      |     |      
+  -50 | 0 | -0050 |      |     |      
+    0 | 0 | 0000  |    0 |   0 |     0
+   50 | 0 | 0050  |      |     |      
+  100 | 0 | 0100  |      |     |      
+  150 | 0 | 0150  |  150 |   0 |   150
+  200 | 0 | 0200  |      |     |      
+  250 | 0 | 0250  |      |     |      
+  300 | 0 | 0300  |  300 |   0 |   300
+  350 | 0 | 0350  |      |     |      
+  400 | 0 | 0400  |      |     |      
+  450 | 0 | 0450  |  450 |   0 |   450
+  500 | 0 | 0500  |      |     |      
+  550 | 0 | 0550  |      |     |      
+  600 | 0 | 0600  |  600 |   0 |   600
+  650 | 0 | 0650  |      |     |      
+  700 | 0 | 0700  |      |     |      
+  750 | 0 | 0750  |  750 |   0 |   750
+(21 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
@@ -430,64 +695,95 @@ SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
          Hash Cond: ((t1.c)::text = (t2.c)::text)
          Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
          ->  Append
-               ->  Seq Scan on prt1_p1 t1
-               ->  Seq Scan on prt1_p2 t1_1
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
          ->  Hash
                ->  Append
                      ->  Hash Join
                            Hash Cond: (t2.a = t3.b)
-                           ->  Seq Scan on prt1_p1 t2
+                           ->  Seq Scan on prt1_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p1 t3
+                                 ->  Seq Scan on prt2_p0 t3
                      ->  Hash Join
                            Hash Cond: (t2_1.a = t3_1.b)
-                           ->  Seq Scan on prt1_p2 t2_1
+                           ->  Seq Scan on prt1_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt2_p2 t3_1
+                                 ->  Seq Scan on prt2_p1 t3_1
                      ->  Hash Join
                            Hash Cond: (t2_2.a = t3_2.b)
-                           ->  Seq Scan on prt1_p3 t2_2
+                           ->  Seq Scan on prt1_p2 t2_2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p3 t3_2
-(26 rows)
+                                 ->  Seq Scan on prt2_p2 t3_2
+                     ->  Hash Join
+                           Hash Cond: (t2_3.a = t3_3.b)
+                           ->  Seq Scan on prt1_p3 t2_3
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p3 t3_3
+                     ->  Hash Join
+                           Hash Cond: (t2_4.a = t3_4.b)
+                           ->  Seq Scan on prt1_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t3_4
+(38 rows)
 
 SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
 			  (SELECT t2.a AS t2a, t3.a AS t3a, t2.b t2b, t2.c t2c, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
 			  ON t1.c = ss.t2c WHERE (t1.b + coalesce(ss.t2b, 0)) = 0 ORDER BY t1.a;
-  a  | t2a | t2c  
------+-----+------
-   0 |   0 | 0000
-  50 |     | 
- 100 |     | 
- 150 | 150 | 0150
- 200 |     | 
- 250 |     | 
- 300 | 300 | 0300
- 350 |     | 
- 400 |     | 
- 450 | 450 | 0450
- 500 |     | 
- 550 |     | 
-(12 rows)
+  a   | t2a  |  t2c  
+------+------+-------
+ -250 |      | 
+ -200 |      | 
+ -150 | -150 | -0150
+ -100 |      | 
+  -50 |      | 
+    0 |    0 | 0000
+   50 |      | 
+  100 |      | 
+  150 |  150 | 0150
+  200 |      | 
+  250 |      | 
+  300 |  300 | 0300
+  350 |      | 
+  400 |      | 
+  450 |  450 | 0450
+  500 |      | 
+  550 |      | 
+  600 |  600 | 0600
+  650 |      | 
+  700 |      | 
+  750 |  750 | 0750
+(21 rows)
 
 --
 -- partitioned by expression
 --
 CREATE TABLE prt1_e (a int, b int, c int) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p0 PARTITION OF prt1_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt1_e_p4 PARTITION OF prt1_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(0, 599, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(600, 799, 2) i;
+CREATE INDEX iprt1_e_p0_ab2 on prt1_e_p1(((a+b)/2));
 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));
+CREATE INDEX iprt1_e_p4_ab2 on prt1_e_p1(((a+b)/2));
 ANALYZE prt1_e;
 CREATE TABLE prt2_e (a int, b int, c int) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p0 PARTITION OF prt2_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt2_e_p4 PARTITION OF prt2_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(0, 599, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(600, 799, 3) i;
 ANALYZE prt2_e;
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b;
@@ -498,32 +794,49 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 =
    ->  Append
          ->  Hash Join
                Hash Cond: (((t2.b + t2.a) / 2) = ((t1.a + t1.b) / 2))
-               ->  Seq Scan on prt2_e_p1 t2
+               ->  Seq Scan on prt2_e_p0 t2
                ->  Hash
-                     ->  Seq Scan on prt1_e_p1 t1
+                     ->  Seq Scan on prt1_e_p0 t1
                            Filter: (c = 0)
          ->  Hash Join
-               Hash Cond: (((t2_1.b + t2_1.a) / 2) = ((t1_1.a + t1_1.b) / 2))
-               ->  Seq Scan on prt2_e_p2 t2_1
+               Hash Cond: (((t1_1.a + t1_1.b) / 2) = ((t2_1.b + t2_1.a) / 2))
+               ->  Seq Scan on prt1_e_p1 t1_1
+                     Filter: (c = 0)
                ->  Hash
-                     ->  Seq Scan on prt1_e_p2 t1_1
-                           Filter: (c = 0)
+                     ->  Seq Scan on prt2_e_p1 t2_1
          ->  Hash Join
                Hash Cond: (((t2_2.b + t2_2.a) / 2) = ((t1_2.a + t1_2.b) / 2))
-               ->  Seq Scan on prt2_e_p3 t2_2
+               ->  Seq Scan on prt2_e_p2 t2_2
                ->  Hash
-                     ->  Seq Scan on prt1_e_p3 t1_2
+                     ->  Seq Scan on prt1_e_p2 t1_2
                            Filter: (c = 0)
-(21 rows)
+         ->  Hash Join
+               Hash Cond: (((t2_3.b + t2_3.a) / 2) = ((t1_3.a + t1_3.b) / 2))
+               ->  Seq Scan on prt2_e_p3 t2_3
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p3 t1_3
+                           Filter: (c = 0)
+         ->  Hash Join
+               Hash Cond: (((t2_4.b + t2_4.a) / 2) = ((t1_4.a + t1_4.b) / 2))
+               ->  Seq Scan on prt2_e_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p4 t1_4
+                           Filter: (c = 0)
+(33 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.c = 0 ORDER BY t1.a, t2.b;
-  a  | c |  b  | c 
------+---+-----+---
-   0 | 0 |   0 | 0
- 150 | 0 | 150 | 0
- 300 | 0 | 300 | 0
- 450 | 0 | 450 | 0
-(4 rows)
+  a   | c |  b   | c 
+------+---+------+---
+ -250 | 0 | -250 | 0
+ -100 | 0 | -100 | 0
+    0 | 0 |    0 | 0
+    0 | 0 |    0 | 0
+  150 | 0 |  150 | 0
+  300 | 0 |  300 | 0
+  450 | 0 |  450 | 0
+  600 | 0 |  600 | 0
+  750 | 0 |  750 | 0
+(9 rows)
 
 --
 -- N-way join
@@ -536,154 +849,232 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
-               Join Filter: (t1.a = ((t3.a + t3.b) / 2))
+               Join Filter: (t1.a = t2.b)
                ->  Hash Join
-                     Hash Cond: (t2.b = t1.a)
-                     ->  Seq Scan on prt2_p1 t2
+                     Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
+                     ->  Seq Scan on prt1_e_p0 t3
                      ->  Hash
-                           ->  Seq Scan on prt1_p1 t1
+                           ->  Seq Scan on prt1_p0 t1
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3
-                     Index Cond: (((a + b) / 2) = t2.b)
+               ->  Index Scan using iprt2_p0_b on prt2_p0 t2
+                     Index Cond: (b = ((t3.a + t3.b) / 2))
          ->  Nested Loop
                Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
                ->  Hash Join
                      Hash Cond: (t2_1.b = t1_1.a)
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
                      ->  Hash
-                           ->  Seq Scan on prt1_p2 t1_1
+                           ->  Seq Scan on prt1_p1 t1_1
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1
+               ->  Index Scan using iprt1_e_p4_ab2 on prt1_e_p1 t3_1
                      Index Cond: (((a + b) / 2) = t2_1.b)
          ->  Nested Loop
                Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
                ->  Hash Join
                      Hash Cond: (t2_2.b = t1_2.a)
-                     ->  Seq Scan on prt2_p3 t2_2
+                     ->  Seq Scan on prt2_p2 t2_2
                      ->  Hash
-                           ->  Seq Scan on prt1_p3 t1_2
+                           ->  Seq Scan on prt1_p2 t1_2
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2
+               ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_2
                      Index Cond: (((a + b) / 2) = t2_2.b)
-(33 rows)
+         ->  Nested Loop
+               Join Filter: (t1_3.a = ((t3_3.a + t3_3.b) / 2))
+               ->  Nested Loop
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                           Index Cond: (b = t1_3.a)
+               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_3
+                     Index Cond: (((a + b) / 2) = t2_3.b)
+         ->  Nested Loop
+               Join Filter: (t1_4.a = t2_4.b)
+               ->  Hash Join
+                     Hash Cond: (((t3_4.a + t3_4.b) / 2) = t1_4.a)
+                     ->  Seq Scan on prt1_e_p4 t3_4
+                     ->  Hash
+                           ->  Seq Scan on prt1_p4 t1_4
+                                 Filter: (b = 0)
+               ->  Index Scan using iprt2_p4_b on prt2_p4 t2_4
+                     Index Cond: (b = ((t3_4.a + t3_4.b) / 2))
+(52 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.b = 0 ORDER BY t1.a, t2.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
-(4 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(8 rows)
 
 EXPLAIN (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.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-                          QUERY PLAN                          
---------------------------------------------------------------
+                             QUERY PLAN                              
+---------------------------------------------------------------------
  Sort
    Sort Key: t1.a, t2.b, ((t3.a + t3.b))
    ->  Append
          ->  Hash Right Join
                Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
-               ->  Seq Scan on prt1_e_p1 t3
+               ->  Seq Scan on prt1_e_p0 t3
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2.b = t1.a)
-                           ->  Seq Scan on prt2_p1 t2
+                           ->  Seq Scan on prt2_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt1_p1 t1
+                                 ->  Seq Scan on prt1_p0 t1
                                        Filter: (b = 0)
          ->  Hash Right Join
                Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a)
-               ->  Seq Scan on prt1_e_p2 t3_1
+               ->  Seq Scan on prt1_e_p1 t3_1
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2_1.b = t1_1.a)
-                           ->  Seq Scan on prt2_p2 t2_1
+                           ->  Seq Scan on prt2_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt1_p2 t1_1
+                                 ->  Seq Scan on prt1_p1 t1_1
                                        Filter: (b = 0)
          ->  Hash Right Join
                Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a)
-               ->  Seq Scan on prt1_e_p3 t3_2
+               ->  Seq Scan on prt1_e_p2 t3_2
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2_2.b = t1_2.a)
-                           ->  Seq Scan on prt2_p3 t2_2
+                           ->  Seq Scan on prt2_p2 t2_2
                            ->  Hash
-                                 ->  Seq Scan on prt1_p3 t1_2
+                                 ->  Seq Scan on prt1_p2 t1_2
                                        Filter: (b = 0)
-(33 rows)
+         ->  Nested Loop Left Join
+               ->  Nested Loop Left Join
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                           Index Cond: (t1_3.a = b)
+               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_3
+                     Index Cond: (t1_3.a = ((a + b) / 2))
+         ->  Hash Right Join
+               Hash Cond: (((t3_4.a + t3_4.b) / 2) = t1_4.a)
+               ->  Seq Scan on prt1_e_p4 t3_4
+               ->  Hash
+                     ->  Hash Right Join
+                           Hash Cond: (t2_4.b = t1_4.a)
+                           ->  Seq Scan on prt2_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt1_p4 t1_4
+                                       Filter: (b = 0)
+(51 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.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-                            QUERY PLAN                             
--------------------------------------------------------------------
+                             QUERY PLAN                              
+---------------------------------------------------------------------
  Sort
    Sort Key: t1.a, t2.b, ((t3.a + t3.b))
    ->  Append
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1.a = ((t3.a + t3.b) / 2))
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p1 t3
+                           ->  Seq Scan on prt1_e_p0 t3
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p1_b on prt2_p1 t2
+               ->  Index Scan using iprt2_p0_b on prt2_p0 t2
                      Index Cond: (t1.a = b)
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p2 t3_1
+                           ->  Seq Scan on prt1_e_p1 t3_1
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p2_b on prt2_p2 t2_1
+               ->  Index Scan using iprt2_p1_b on prt2_p1 t2_1
                      Index Cond: (t1_1.a = b)
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p3 t3_2
+                           ->  Seq Scan on prt1_e_p2 t3_2
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_2
+               ->  Index Scan using iprt2_p2_b on prt2_p2 t2_2
                      Index Cond: (t1_2.a = b)
-(30 rows)
+         ->  Nested Loop Left Join
+               ->  Nested Loop Left Join
+                     ->  Seq Scan on prt1_e_p3 t3_3
+                           Filter: (c = 0)
+                     ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                           Index Cond: (a = ((t3_3.a + t3_3.b) / 2))
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (t1_3.a = b)
+         ->  Nested Loop Left Join
+               ->  Hash Right Join
+                     Hash Cond: (t1_4.a = ((t3_4.a + t3_4.b) / 2))
+                     ->  Seq Scan on prt1_p4 t1_4
+                     ->  Hash
+                           ->  Seq Scan on prt1_e_p4 t3_4
+                                 Filter: (c = 0)
+               ->  Index Scan using iprt2_p4_b on prt2_p4 t2_4
+                     Index Cond: (t1_4.a = b)
+(47 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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 -- Cases with non-nullable expressions in subquery results;
 -- make sure these go to null as expected
@@ -692,21 +1083,34 @@ SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * F
                                                    QUERY PLAN                                                   
 ----------------------------------------------------------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b))
+   Sort Key: prt1_p0.a, prt2_p0.b, ((prt1_e_p0.a + prt1_e_p0.b))
    ->  Append
          ->  Hash Full Join
-               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 Cond: (prt1_p0.a = ((prt1_e_p0.a + prt1_e_p0.b) / 2))
+               Filter: ((prt1_p0.a = (50)) OR (prt2_p0.b = (75)) OR (((prt1_e_p0.a + prt1_e_p0.b) / 2) = (50)))
                ->  Hash Full Join
-                     Hash Cond: (prt1_p1.a = prt2_p1.b)
-                     ->  Seq Scan on prt1_p1
+                     Hash Cond: (prt1_p0.a = prt2_p0.b)
+                     ->  Seq Scan on prt1_p0
                            Filter: (b = 0)
                      ->  Hash
-                           ->  Seq Scan on prt2_p1
+                           ->  Seq Scan on prt2_p0
                                  Filter: (a = 0)
                ->  Hash
-                     ->  Seq Scan on prt1_e_p1
+                     ->  Seq Scan on prt1_e_p0
                            Filter: (c = 0)
+         ->  Hash Full Join
+               Hash Cond: (((prt1_e_p1.a + prt1_e_p1.b) / 2) = prt1_p1.a)
+               Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50)))
+               ->  Seq Scan on prt1_e_p1
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Hash Full Join
+                           Hash Cond: (prt1_p1.a = prt2_p1.b)
+                           ->  Seq Scan on prt1_p1
+                                 Filter: (b = 0)
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p1
+                                       Filter: (a = 0)
          ->  Hash Full Join
                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)))
@@ -733,7 +1137,20 @@ SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * F
                ->  Hash
                      ->  Seq Scan on prt1_e_p3
                            Filter: (c = 0)
-(42 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt1_p4.a = ((prt1_e_p4.a + prt1_e_p4.b) / 2))
+               Filter: ((prt1_p4.a = (50)) OR (prt2_p4.b = (75)) OR (((prt1_e_p4.a + prt1_e_p4.b) / 2) = (50)))
+               ->  Hash Full Join
+                     Hash Cond: (prt1_p4.a = prt2_p4.b)
+                     ->  Seq Scan on prt1_p4
+                           Filter: (b = 0)
+                     ->  Hash
+                           ->  Seq Scan on prt2_p4
+                                 Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p4
+                           Filter: (c = 0)
+(68 rows)
 
 SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 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 
@@ -751,172 +1168,260 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHER
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
-               Join Filter: (t1.a = t1_3.b)
+               Join Filter: (t1.a = t1_5.b)
                ->  HashAggregate
-                     Group Key: t1_3.b
+                     Group Key: t1_5.b
                      ->  Hash Join
-                           Hash Cond: (((t2.a + t2.b) / 2) = t1_3.b)
-                           ->  Seq Scan on prt1_e_p1 t2
+                           Hash Cond: (((t2.a + t2.b) / 2) = t1_5.b)
+                           ->  Seq Scan on prt1_e_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p1 t1_3
+                                 ->  Seq Scan on prt2_p0 t1_5
                                        Filter: (a = 0)
-               ->  Index Scan using iprt1_p1_a on prt1_p1 t1
+               ->  Index Scan using iprt1_p0_a on prt1_p0 t1
                      Index Cond: (a = ((t2.a + t2.b) / 2))
                      Filter: (b = 0)
          ->  Nested Loop
-               Join Filter: (t1_1.a = t1_4.b)
+               Join Filter: (t1_1.a = t1_6.b)
                ->  HashAggregate
-                     Group Key: t1_4.b
+                     Group Key: t1_6.b
                      ->  Hash Join
-                           Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_4.b)
-                           ->  Seq Scan on prt1_e_p2 t2_1
+                           Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_6.b)
+                           ->  Seq Scan on prt1_e_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt2_p2 t1_4
+                                 ->  Seq Scan on prt2_p1 t1_6
                                        Filter: (a = 0)
-               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_1
+               ->  Index Scan using iprt1_p1_a on prt1_p1 t1_1
                      Index Cond: (a = ((t2_1.a + t2_1.b) / 2))
                      Filter: (b = 0)
          ->  Nested Loop
-               Join Filter: (t1_2.a = t1_5.b)
+               Join Filter: (t1_2.a = t1_7.b)
                ->  HashAggregate
-                     Group Key: t1_5.b
+                     Group Key: t1_7.b
                      ->  Nested Loop
-                           ->  Seq Scan on prt2_p3 t1_5
+                           ->  Seq Scan on prt2_p2 t1_7
                                  Filter: (a = 0)
-                           ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_2
-                                 Index Cond: (((a + b) / 2) = t1_5.b)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
+                           ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t2_2
+                                 Index Cond: (((a + b) / 2) = t1_7.b)
+               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_2
                      Index Cond: (a = ((t2_2.a + t2_2.b) / 2))
                      Filter: (b = 0)
-(41 rows)
+         ->  Nested Loop
+               Join Filter: (t1_3.a = t1_8.b)
+               ->  HashAggregate
+                     Group Key: t1_8.b
+                     ->  Nested Loop
+                           ->  Seq Scan on prt2_p3 t1_8
+                                 Filter: (a = 0)
+                           ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_3
+                                 Index Cond: (((a + b) / 2) = t1_8.b)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = ((t2_3.a + t2_3.b) / 2))
+                     Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: (t1_4.a = t1_9.b)
+               ->  HashAggregate
+                     Group Key: t1_9.b
+                     ->  Hash Join
+                           Hash Cond: (((t2_4.a + t2_4.b) / 2) = t1_9.b)
+                           ->  Seq Scan on prt1_e_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t1_9
+                                       Filter: (a = 0)
+               ->  Index Scan using iprt1_p4_a on prt1_p4 t1_4
+                     Index Cond: (a = ((t2_4.a + t2_4.b) / 2))
+                     Filter: (b = 0)
+(66 rows)
 
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.a = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 EXPLAIN (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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-                               QUERY PLAN                                
--------------------------------------------------------------------------
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_3.b
+                     Group Key: t1_5.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_3.b = ((t1_6.a + t1_6.b) / 2))
-                           ->  Seq Scan on prt2_p1 t1_3
+                           Hash Cond: (t1_5.b = ((t1_10.a + t1_10.b) / 2))
+                           ->  Seq Scan on prt2_p0 t1_5
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p1 t1_6
+                                 ->  Seq Scan on prt1_e_p0 t1_10
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p1_a on prt1_p1 t1
-                     Index Cond: (a = t1_3.b)
+               ->  Index Scan using iprt1_p0_a on prt1_p0 t1
+                     Index Cond: (a = t1_5.b)
                      Filter: (b = 0)
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_4.b
+                     Group Key: t1_6.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_4.b = ((t1_7.a + t1_7.b) / 2))
-                           ->  Seq Scan on prt2_p2 t1_4
+                           Hash Cond: (t1_6.b = ((t1_11.a + t1_11.b) / 2))
+                           ->  Seq Scan on prt2_p1 t1_6
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p2 t1_7
+                                 ->  Seq Scan on prt1_e_p1 t1_11
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_1
-                     Index Cond: (a = t1_4.b)
+               ->  Index Scan using iprt1_p1_a on prt1_p1 t1_1
+                     Index Cond: (a = t1_6.b)
                      Filter: (b = 0)
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_5.b
+                     Group Key: t1_7.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_5.b = ((t1_8.a + t1_8.b) / 2))
-                           ->  Seq Scan on prt2_p3 t1_5
+                           Hash Cond: (t1_7.b = ((t1_12.a + t1_12.b) / 2))
+                           ->  Seq Scan on prt2_p2 t1_7
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p3 t1_8
+                                 ->  Seq Scan on prt1_e_p2 t1_12
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
-                     Index Cond: (a = t1_5.b)
+               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_2
+                     Index Cond: (a = t1_7.b)
                      Filter: (b = 0)
-(39 rows)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t1_8.b
+                     ->  Hash Semi Join
+                           Hash Cond: (t1_8.b = ((t1_13.a + t1_13.b) / 2))
+                           ->  Seq Scan on prt2_p3 t1_8
+                           ->  Hash
+                                 ->  Seq Scan on prt1_e_p3 t1_13
+                                       Filter: (c = 0)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t1_8.b)
+                     Filter: (b = 0)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t1_9.b
+                     ->  Hash Semi Join
+                           Hash Cond: (t1_9.b = ((t1_14.a + t1_14.b) / 2))
+                           ->  Seq Scan on prt2_p4 t1_9
+                           ->  Hash
+                                 ->  Seq Scan on prt1_e_p4 t1_14
+                                       Filter: (c = 0)
+               ->  Index Scan using iprt1_p4_a on prt1_p4 t1_4
+                     Index Cond: (a = t1_9.b)
+                     Filter: (b = 0)
+(63 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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 -- test merge joins
 SET enable_hashjoin TO off;
 SET enable_nestloop TO off;
 EXPLAIN (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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-                           QUERY PLAN                           
-----------------------------------------------------------------
+                            QUERY PLAN                            
+------------------------------------------------------------------
  Merge Append
    Sort Key: t1.a
    ->  Merge Semi Join
-         Merge Cond: (t1.a = t1_3.b)
+         Merge Cond: (t1.a = t1_5.b)
          ->  Sort
                Sort Key: t1.a
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_3.b = (((t1_6.a + t1_6.b) / 2)))
+               Merge Cond: (t1_5.b = (((t1_10.a + t1_10.b) / 2)))
                ->  Sort
-                     Sort Key: t1_3.b
-                     ->  Seq Scan on prt2_p1 t1_3
+                     Sort Key: t1_5.b
+                     ->  Seq Scan on prt2_p0 t1_5
                ->  Sort
-                     Sort Key: (((t1_6.a + t1_6.b) / 2))
-                     ->  Seq Scan on prt1_e_p1 t1_6
+                     Sort Key: (((t1_10.a + t1_10.b) / 2))
+                     ->  Seq Scan on prt1_e_p0 t1_10
                            Filter: (c = 0)
    ->  Merge Semi Join
-         Merge Cond: (t1_1.a = t1_4.b)
+         Merge Cond: (t1_1.a = t1_6.b)
          ->  Sort
                Sort Key: t1_1.a
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_4.b = (((t1_7.a + t1_7.b) / 2)))
+               Merge Cond: (t1_6.b = (((t1_11.a + t1_11.b) / 2)))
                ->  Sort
-                     Sort Key: t1_4.b
-                     ->  Seq Scan on prt2_p2 t1_4
+                     Sort Key: t1_6.b
+                     ->  Seq Scan on prt2_p1 t1_6
                ->  Sort
-                     Sort Key: (((t1_7.a + t1_7.b) / 2))
-                     ->  Seq Scan on prt1_e_p2 t1_7
+                     Sort Key: (((t1_11.a + t1_11.b) / 2))
+                     ->  Seq Scan on prt1_e_p1 t1_11
                            Filter: (c = 0)
    ->  Merge Semi Join
-         Merge Cond: (t1_2.a = t1_5.b)
+         Merge Cond: (t1_2.a = t1_7.b)
          ->  Sort
                Sort Key: t1_2.a
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_5.b = (((t1_8.a + t1_8.b) / 2)))
+               Merge Cond: (t1_7.b = (((t1_12.a + t1_12.b) / 2)))
                ->  Sort
-                     Sort Key: t1_5.b
-                     ->  Seq Scan on prt2_p3 t1_5
+                     Sort Key: t1_7.b
+                     ->  Seq Scan on prt2_p2 t1_7
                ->  Sort
-                     Sort Key: (((t1_8.a + t1_8.b) / 2))
-                     ->  Seq Scan on prt1_e_p3 t1_8
+                     Sort Key: (((t1_12.a + t1_12.b) / 2))
+                     ->  Seq Scan on prt1_e_p2 t1_12
                            Filter: (c = 0)
-(47 rows)
+   ->  Merge Semi Join
+         Merge Cond: (t1_3.a = t1_8.b)
+         ->  Sort
+               Sort Key: t1_3.a
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Merge Semi Join
+               Merge Cond: (t1_8.b = (((t1_13.a + t1_13.b) / 2)))
+               ->  Sort
+                     Sort Key: t1_8.b
+                     ->  Seq Scan on prt2_p3 t1_8
+               ->  Sort
+                     Sort Key: (((t1_13.a + t1_13.b) / 2))
+                     ->  Seq Scan on prt1_e_p3 t1_13
+                           Filter: (c = 0)
+   ->  Merge Semi Join
+         Merge Cond: (t1_4.a = t1_9.b)
+         ->  Sort
+               Sort Key: t1_4.a
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Merge Semi Join
+               Merge Cond: (t1_9.b = (((t1_14.a + t1_14.b) / 2)))
+               ->  Sort
+                     Sort Key: t1_9.b
+                     ->  Seq Scan on prt2_p4 t1_9
+               ->  Sort
+                     Sort Key: (((t1_14.a + t1_14.b) / 2))
+                     ->  Seq Scan on prt1_e_p4 t1_14
+                           Filter: (c = 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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
@@ -933,14 +1438,14 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a)
                            ->  Sort
                                  Sort Key: (((t3.a + t3.b) / 2))
-                                 ->  Seq Scan on prt1_e_p1 t3
+                                 ->  Seq Scan on prt1_e_p0 t3
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1.a
-                                 ->  Seq Scan on prt1_p1 t1
+                                 ->  Seq Scan on prt1_p0 t1
                ->  Sort
                      Sort Key: t2.b
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
          ->  Merge Left Join
                Merge Cond: (t1_1.a = t2_1.b)
                ->  Sort
@@ -949,14 +1454,14 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a)
                            ->  Sort
                                  Sort Key: (((t3_1.a + t3_1.b) / 2))
-                                 ->  Seq Scan on prt1_e_p2 t3_1
+                                 ->  Seq Scan on prt1_e_p1 t3_1
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1_1.a
-                                 ->  Seq Scan on prt1_p2 t1_1
+                                 ->  Seq Scan on prt1_p1 t1_1
                ->  Sort
                      Sort Key: t2_1.b
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
          ->  Merge Left Join
                Merge Cond: (t1_2.a = t2_2.b)
                ->  Sort
@@ -965,32 +1470,74 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a)
                            ->  Sort
                                  Sort Key: (((t3_2.a + t3_2.b) / 2))
-                                 ->  Seq Scan on prt1_e_p3 t3_2
+                                 ->  Seq Scan on prt1_e_p2 t3_2
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1_2.a
-                                 ->  Seq Scan on prt1_p3 t1_2
+                                 ->  Seq Scan on prt1_p2 t1_2
                ->  Sort
                      Sort Key: t2_2.b
-                     ->  Seq Scan on prt2_p3 t2_2
-(51 rows)
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Merge Left Join
+               Merge Cond: (t1_3.a = t2_3.b)
+               ->  Sort
+                     Sort Key: t1_3.a
+                     ->  Merge Left Join
+                           Merge Cond: ((((t3_3.a + t3_3.b) / 2)) = t1_3.a)
+                           ->  Sort
+                                 Sort Key: (((t3_3.a + t3_3.b) / 2))
+                                 ->  Seq Scan on prt1_e_p3 t3_3
+                                       Filter: (c = 0)
+                           ->  Sort
+                                 Sort Key: t1_3.a
+                                 ->  Seq Scan on prt1_p3 t1_3
+               ->  Sort
+                     Sort Key: t2_3.b
+                     ->  Seq Scan on prt2_p3 t2_3
+         ->  Merge Left Join
+               Merge Cond: (t1_4.a = t2_4.b)
+               ->  Sort
+                     Sort Key: t1_4.a
+                     ->  Merge Left Join
+                           Merge Cond: ((((t3_4.a + t3_4.b) / 2)) = t1_4.a)
+                           ->  Sort
+                                 Sort Key: (((t3_4.a + t3_4.b) / 2))
+                                 ->  Seq Scan on prt1_e_p4 t3_4
+                                       Filter: (c = 0)
+                           ->  Sort
+                                 Sort Key: t1_4.a
+                                 ->  Seq Scan on prt1_p4 t1_4
+               ->  Sort
+                     Sort Key: t2_4.b
+                     ->  Seq Scan on prt2_p4 t2_4
+(83 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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 -- MergeAppend on nullable column
 EXPLAIN (COSTS OFF)
@@ -998,8 +1545,18 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
                         QUERY PLAN                         
 -----------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Merge Left Join
+               Merge Cond: (prt1_p0.a = b)
+               ->  Sort
+                     Sort Key: prt1_p0.a
+                     ->  Seq Scan on prt1_p0
+                           Filter: ((a < 450) AND (b = 0))
+               ->  Sort
+                     Sort Key: b
+                     ->  Result
+                           One-Time Filter: false
          ->  Merge Left Join
                Merge Cond: (prt1_p1.a = b)
                ->  Sort
@@ -1020,21 +1577,26 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
                      Sort Key: prt2_p2.b
                      ->  Seq Scan on prt2_p2
                            Filter: (b > 250)
-(23 rows)
+(33 rows)
 
 SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
-  a  |  b  
------+-----
-   0 |    
-  50 |    
- 100 |    
- 150 |    
- 200 |    
- 250 |    
- 300 | 300
- 350 |    
- 400 |    
-(9 rows)
+  a   |  b  
+------+-----
+ -250 |    
+ -200 |    
+ -150 |    
+ -100 |    
+  -50 |    
+    0 |    
+   50 |    
+  100 |    
+  150 |    
+  200 |    
+  250 |    
+  300 | 300
+  350 |    
+  400 |    
+(14 rows)
 
 -- merge join when expression with whole-row reference needs to be sorted;
 -- partitionwise join does not apply
@@ -1048,175 +1610,2412 @@ SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.
          Sort Key: t1.a, ((((t1.*)::prt1))::text)
          ->  Result
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
-                     ->  Seq Scan on prt1_p2 t1_1
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p0 t1
+                     ->  Seq Scan on prt1_p1 t1_1
+                     ->  Seq Scan on prt1_p2 t1_2
+                     ->  Seq Scan on prt1_p3 t1_3
+                     ->  Seq Scan on prt1_p4 t1_4
    ->  Sort
          Sort Key: t2.b, ((((t2.*)::prt2))::text)
          ->  Result
                ->  Append
-                     ->  Seq Scan on prt2_p1 t2
-                     ->  Seq Scan on prt2_p2 t2_1
-                     ->  Seq Scan on prt2_p3 t2_2
-(16 rows)
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+(20 rows)
 
 SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
- a  | b  
-----+----
-  0 |  0
-  6 |  6
- 12 | 12
- 18 | 18
- 24 | 24
-(5 rows)
+  a  |  b  
+-----+-----
+ -24 | -24
+ -18 | -18
+ -12 | -12
+  -6 |  -6
+   0 |   0
+   6 |   6
+  12 |  12
+  18 |  18
+  24 |  24
+(9 rows)
 
 RESET enable_hashjoin;
 RESET enable_nestloop;
---
--- partitioned by multiple columns
---
-CREATE TABLE prt1_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 2) i;
-ANALYZE prt1_m;
-CREATE TABLE prt2_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 3) i;
-ANALYZE prt2_m;
+-- test default partition behavior for range, partition-wise join is not
+-- possible since more than one partition on one side matches default partition
+-- on the other side. Default partition from prt1 matches default partition and
+-- prt2_p4 from prt2 and default partition from prt2 matches default partition
+-- and prt1_p0 from prt1
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
+ANALYZE prt2;
 EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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                                                             
-------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p4 t2_3
+               ->  Seq Scan on prt2_p3 t2_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_4
+                           Filter: (b = 0)
+(22 rows)
+
+-- partition-wise join should be possible when we drop the first and last
+-- partitions from both sides
+ALTER TABLE prt1 DETACH PARTITION prt1_p0;
+ALTER TABLE prt1 DETACH PARTITION prt1_p4;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p0;
+ALTER TABLE prt2 DETACH PARTITION prt2_p4;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p1 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p2 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p3 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p3 t1_2
+                           Filter: (b = 0)
+(21 rows)
+
+-- restore the partitioned tables for rest of the tests
+ALTER TABLE prt1 ATTACH PARTITION prt1_p0 FOR VALUES FROM (MINVALUE) TO (0);
+ALTER TABLE prt1 ATTACH PARTITION prt1_p4 FOR VALUES FROM (600) TO (800);
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt1;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p0 FOR VALUES FROM (-250) TO (0);
+ALTER TABLE prt2 ATTACH PARTITION prt2_p4 FOR VALUES FROM (600) TO (MAXVALUE);
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt2;
+-- Add an extra partition to prt2 , Partition-wise join is possible with
+-- extra partitions on inner side are allowed
+DROP TABLE prt2_p4;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (800);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (800) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999) i WHERE i % 3 = 0;
+ANALYZE prt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p0 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+         ->  Nested Loop
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+  a   |   c   | a |   c   
+------+-------+---+-------
+ -150 | -0150 | 0 | -0150
+    0 | 0000  | 0 | 0000
+  150 | 0150  | 0 | 0150
+  300 | 0300  | 0 | 0300
+  450 | 0450  | 0 | 0450
+  600 | 0600  | 0 | 0600
+  750 | 0750  | 0 | 0750
+(7 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p0 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+         ->  Hash Right Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Hash Right Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (t1_3.a = b)
+         ->  Hash Right Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+  a   |   c   | a |   c   
+------+-------+---+-------
+ -250 | -0250 |   | 
+ -200 | -0200 |   | 
+ -150 | -0150 | 0 | -0150
+ -100 | -0100 |   | 
+  -50 | -0050 |   | 
+    0 | 0000  | 0 | 0000
+   50 | 0050  |   | 
+  100 | 0100  |   | 
+  150 | 0150  | 0 | 0150
+  200 | 0200  |   | 
+  250 | 0250  |   | 
+  300 | 0300  | 0 | 0300
+  350 | 0350  |   | 
+  400 | 0400  |   | 
+  450 | 0450  | 0 | 0450
+  500 | 0500  |   | 
+  550 | 0550  |   | 
+  600 | 0600  | 0 | 0600
+  650 | 0650  |   | 
+  700 | 0700  |   | 
+  750 | 0750  | 0 | 0750
+(21 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Semi Join
+               Hash Cond: (t1.a = t2.b)
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0 t2
+         ->  Hash Semi Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Only Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(32 rows)
+
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Append
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
+                     Index Cond: (a = t1.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2_1
+                     Index Cond: (a = t1_1.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
+                     Index Cond: (a = t1_2.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+                     Index Cond: (a = t1_3.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+                     Index Cond: (a = t1_4.b)
+(28 rows)
+
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+ a |  b   |   c   
+---+------+-------
+ 0 | -150 | -0150
+ 0 |    0 | 0000
+ 0 |  150 | 0150
+ 0 |  300 | 0300
+ 0 |  450 | 0450
+ 0 |  600 | 0600
+ 0 |  750 | 0750
+(7 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: (t1.a = t2.b)
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0 t2
+         ->  Hash Anti Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+         ->  Hash Anti Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Only Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Anti Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(32 rows)
+
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a   | b |   c   
+------+---+-------
+ -250 | 0 | -0250
+ -200 | 0 | -0200
+ -100 | 0 | -0100
+  -50 | 0 | -0050
+   50 | 0 | 0050
+  100 | 0 | 0100
+  200 | 0 | 0200
+  250 | 0 | 0250
+  350 | 0 | 0350
+  400 | 0 | 0400
+  500 | 0 | 0500
+  550 | 0 | 0550
+  650 | 0 | 0650
+  700 | 0 | 0700
+(14 rows)
+
+-- 3-way join when not every pair of joining relation can use partition-wise
+-- join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t3.c
+   ->  Append
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p0 t2
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p0_a on prt1_p0 t3
+                           Index Cond: (a = t2.b)
+               ->  Index Only Scan using iprt1_p0_a on prt1_p0 t1
+                     Index Cond: (a = t2.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Hash
+                     ->  Hash Join
+                           Hash Cond: (t3_1.a = t2_1.b)
+                           ->  Seq Scan on prt1_p1 t3_1
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p1 t2_1
+                                       Filter: (a = 0)
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p2 t2_2
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p2_a on prt1_p2 t3_2
+                           Index Cond: (a = t2_2.b)
+               ->  Index Only Scan using iprt1_p2_a on prt1_p2 t1_2
+                     Index Cond: (a = t2_2.b)
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p3_a on prt1_p3 t3_3
+                           Index Cond: (a = t2_3.b)
+               ->  Index Only Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Hash Join
+                           Hash Cond: (t3_4.a = t2_4.b)
+                           ->  Seq Scan on prt1_p4 t3_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t2_4
+                                       Filter: (a = 0)
+(47 rows)
+
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+  a   | a |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+-- partition-wise join can not handle missing partition on the inner side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.b
+   ->  Hash Right Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p1 t2_1
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p2 t2_2
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p5 t2_5
+                           Filter: (a = 0)
+(24 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE coalesce(t1.b, 0) + coalesce(t2.a, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: (t1.a = t2.b)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.a, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(19 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE prt2_p4;
+DROP TABLE prt2_p5;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (700);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (700) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999, 3) i;
+ANALYZE prt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Right Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.a;
+                 QUERY PLAN                 
+--------------------------------------------
+ Hash Right Join
+   Hash Cond: (t1.a = t2.b)
+   ->  Append
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t2_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t2_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t2_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t2_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t2_5
+                     Filter: (a = 0)
+(22 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b + t2.a = 0 ORDER BY t1.a, t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Join
+         Hash Cond: (t1.a = t2.b)
+         Join Filter: ((t1.b + t2.a) = 0)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(19 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Semi Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Semi Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+--
+-- partitioned by multiple columns
+--
+CREATE TABLE prt1_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_m;
+CREATE TABLE prt2_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_m;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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
+   Sort Key: prt1_m_p1.a, prt2_m_p1.b
+   ->  Append
+         ->  Hash Full Join
+               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 prt1_m_p1
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p1
+                           Filter: (c = 0)
+         ->  Hash Full Join
+               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 prt1_m_p2
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p2
+                           Filter: (c = 0)
+         ->  Hash Full Join
+               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 prt1_m_p3
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p3
+                           Filter: (c = 0)
+(24 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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 | 0 |   0 | 0
+  50 | 0 |     |  
+ 100 | 0 |     |  
+ 150 | 0 | 150 | 0
+ 200 | 0 |     |  
+ 250 | 0 |     |  
+ 300 | 0 | 300 | 0
+ 350 | 0 |     |  
+ 400 | 0 |     |  
+ 450 | 0 | 450 | 0
+ 500 | 0 |     |  
+ 550 | 0 |     |  
+     |   |  75 | 0
+     |   | 225 | 0
+     |   | 375 | 0
+     |   | 525 | 0
+(16 rows)
+
+--
+-- tests for list partitioned tables.
+--
+\set part_mod 17
+\set cond_mod 47
+\set num_rows 500
+CREATE TABLE plt1 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0001','0002','0003');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0008','0009');
+CREATE TABLE plt1_p4 PARTITION OF plt1 FOR VALUES IN ('0000','0010');
+INSERT INTO plt1 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (7, 11, 12, 13, 14, 15, 16);
+ANALYSE plt1;
+-- plt2 have missing starting 0001, additional 0007, missing ending 0010
+-- and additional 0011 and 0012 bounds
+CREATE TABLE plt2 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0002','0003');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0007','0008','0009');
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000','0011','0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 10, 13, 14, 15, 16);
+ANALYSE plt2;
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Left Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t2_2.c)::text = (t1_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + t2_2.b) = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on plt1_p2 t1_2
+         ->  Hash Right Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 0011
+(6 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                               QUERY PLAN                                
+-------------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Append
+         ->  Hash Full Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Full Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Full Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Full Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 0011
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 470 | 0 | 0011
+(1 row)
+
+--
+-- 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 ('0002', '0003');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0004', '0005', '0006');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0008', '0009');
+CREATE TABLE plt1_e_p4 PARTITION OF plt1_e FOR VALUES IN ('0000');
+INSERT INTO plt1_e SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 7, 10, 11, 12, 13, 14, 15, 16);
+ANALYZE plt1_e;
+-- test partition matching with N-way join
+EXPLAIN (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.b = t2.b AND 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                                           
+------------------------------------------------------------------------------------------------
+ GroupAggregate
+   Group Key: t1.c, t2.c, t3.c
+   ->  Sort
+         Sort Key: t1.c, t3.c
+         ->  Append
+               ->  Hash Join
+                     Hash Cond: ((t1.c)::text = ltrim(t3.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t2.b = t1.b) AND ((t2.c)::text = (t1.c)::text))
+                           ->  Seq Scan on plt2_p4 t2
+                           ->  Hash
+                                 ->  Seq Scan on plt1_p4 t1
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p4 t3
+               ->  Hash Join
+                     Hash Cond: ((t1_1.c)::text = ltrim(t3_1.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t1_1.b = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
+                           ->  Seq Scan on plt1_p1 t1_1
+                           ->  Hash
+                                 ->  Seq Scan on plt2_p1 t2_1
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p1 t3_1
+               ->  Hash Join
+                     Hash Cond: ((t1_2.c)::text = ltrim(t3_2.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t1_2.b = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
+                           ->  Seq Scan on plt1_p2 t1_2
+                           ->  Hash
+                                 ->  Seq Scan on plt2_p2 t2_2
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p2 t3_2
+               ->  Hash Join
+                     Hash Cond: ((t1_3.c)::text = ltrim(t3_3.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t2_3.b = t1_3.b) AND ((t2_3.c)::text = (t1_3.c)::text))
+                           ->  Seq Scan on plt2_p3 t2_3
+                           ->  Hash
+                                 ->  Seq Scan on plt1_p3 t1_3
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p3 t3_3
+(41 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.b = t2.b AND 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   
+----------------------+---------------------+----------------------+------+------+------
+ 246.5000000000000000 | 22.4666666666666667 | 268.9666666666666667 | 0000 | 0000 | 0000
+ 248.5000000000000000 | 21.3333333333333333 | 269.8333333333333333 | 0002 | 0002 | 0002
+ 249.5000000000000000 | 22.3333333333333333 | 271.8333333333333333 | 0003 | 0003 | 0003
+ 250.5000000000000000 | 23.3333333333333333 | 273.8333333333333333 | 0004 | 0004 | 0004
+ 251.5000000000000000 | 22.7666666666666667 | 274.2666666666666667 | 0005 | 0005 | 0005
+ 252.5000000000000000 | 22.2000000000000000 | 274.7000000000000000 | 0006 | 0006 | 0006
+ 246.0000000000000000 | 23.9655172413793103 | 269.9655172413793103 | 0008 | 0008 | 0008
+ 247.0000000000000000 | 23.3448275862068966 | 270.3448275862068966 | 0009 | 0009 | 0009
+(8 rows)
+
+-- Add an extra partition to plt2 , Partition-wise join is possible with
+-- partitions on inner side are allowed
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (13, 14);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Hash Right Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+                     ->  Seq Scan on plt2_p5 t2_4
+(17 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      |  47 | 0013
+     |      | 470 | 0011
+     |      | 235 | 0014
+(8 rows)
+
+-- full join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+                     ->  Seq Scan on plt2_p5 t2_4
+(17 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      |  47 | 0013
+     |      | 235 | 0014
+     |      | 470 | 0011
+(10 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(21 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+  47 | 0 | 0013
+ 235 | 0 | 0014
+ 470 | 0 | 0011
+(3 rows)
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt2_p5;
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0001','0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (1, 13, 14);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Join Filter: ((t1.b + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Left Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Hash Right Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt2_p4 t2
+                                 ->  Seq Scan on plt2_p5 t2_1
+                                 ->  Seq Scan on plt2_p1 t2_2
+                                 ->  Seq Scan on plt2_p2 t2_3
+                                 ->  Seq Scan on plt2_p3 t2_4
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt1_p4 t2
+                                 ->  Seq Scan on plt1_p1 t2_1
+                                 ->  Seq Scan on plt1_p2 t2_2
+                                 ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                     QUERY PLAN                     
+----------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Nested Loop Anti Join
+         Join Filter: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Materialize
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(20 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(21 rows)
+
+-- partition have a NULL on one side, Partition-wise join is possible with
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- in this case NULL will be treated as addition partition bounds.
+DROP TABLE plt2_p5;
+DROP TABLE plt2_p4;
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000',NULL,'0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, case when i % :part_mod = 11 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (0,11,12);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Left Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t2_2.c)::text = (t1_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + t2_2.b) = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on plt1_p2 t1_2
+         ->  Hash Right Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 
+(6 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                               QUERY PLAN                                
+-------------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Append
+         ->  Hash Full Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Full Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Full Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Full Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b | c 
+-----+---+---
+ 470 | 0 | 
+(1 row)
+
+-- partition have a NULL on both side with different partition bounds w.r.t other side
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt1_p3;
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN (NULL,'0008','0009');
+INSERT INTO plt1 SELECT i, i % :cond_mod, case when i % :part_mod = 7 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (7,8,9);
+ANALYZE plt1;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Join Filter: ((t1.b + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Right Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
  Sort
-   Sort Key: prt1_m_p1.a, prt2_m_p1.b
-   ->  Append
-         ->  Hash Full Join
-               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 prt1_m_p1
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p1
-                           Filter: (c = 0)
-         ->  Hash Full Join
-               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 prt1_m_p2
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p2
-                           Filter: (c = 0)
-         ->  Hash Full Join
-               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 prt1_m_p3
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p3
-                           Filter: (c = 0)
-(24 rows)
+   Sort Key: t2.a
+   ->  Hash Left Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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 | 0 |   0 | 0
-  50 | 0 |     |  
- 100 | 0 |     |  
- 150 | 0 | 150 | 0
- 200 | 0 |     |  
- 250 | 0 |     |  
- 300 | 0 | 300 | 0
- 350 | 0 |     |  
- 400 | 0 |     |  
- 450 | 0 | 450 | 0
- 500 | 0 |     |  
- 550 | 0 |     |  
-     |   |  75 | 0
-     |   | 225 | 0
-     |   | 375 | 0
-     |   | 525 | 0
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
 (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;
-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;
---
--- 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;
--- test partition matching with N-way join
+-- semi join
 EXPLAIN (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.b = t2.b AND 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                                   
---------------------------------------------------------------------------------
- GroupAggregate
-   Group Key: t1.c, t2.c, t3.c
-   ->  Sort
-         Sort Key: t1.c, t3.c
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
          ->  Append
-               ->  Hash Join
-                     Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-                           ->  Seq Scan on plt1_p1 t1
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p1 t2
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p1 t3
-               ->  Hash Join
-                     Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-                           ->  Seq Scan on plt1_p2 t1_1
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p2 t2_1
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p2 t3_1
-               ->  Hash Join
-                     Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-                           ->  Seq Scan on plt1_p3 t1_2
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p3 t2_2
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p3 t3_2
-(32 rows)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt2_p4 t2
+                                 ->  Seq Scan on plt2_p1 t2_1
+                                 ->  Seq Scan on plt2_p2 t2_2
+                                 ->  Seq Scan on plt2_p3 t2_3
+(22 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.b = t2.b AND 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
-  75.0000000000000000 |  75.0000000000000000 |  148.0000000000000000 | 0001 | 0001 | A0001
- 123.0000000000000000 | 123.0000000000000000 |  248.0000000000000000 | 0002 | 0002 | A0002
- 174.0000000000000000 | 174.0000000000000000 |  348.0000000000000000 | 0003 | 0003 | A0003
- 225.0000000000000000 | 225.0000000000000000 |  448.0000000000000000 | 0004 | 0004 | A0004
- 273.0000000000000000 | 273.0000000000000000 |  548.0000000000000000 | 0005 | 0005 | A0005
- 324.0000000000000000 | 324.0000000000000000 |  648.0000000000000000 | 0006 | 0006 | A0006
- 375.0000000000000000 | 375.0000000000000000 |  748.0000000000000000 | 0007 | 0007 | A0007
- 423.0000000000000000 | 423.0000000000000000 |  848.0000000000000000 | 0008 | 0008 | A0008
- 474.0000000000000000 | 474.0000000000000000 |  948.0000000000000000 | 0009 | 0009 | A0009
- 525.0000000000000000 | 525.0000000000000000 | 1048.0000000000000000 | 0010 | 0010 | A0010
- 573.0000000000000000 | 573.0000000000000000 | 1148.0000000000000000 | 0011 | 0011 | A0011
-(12 rows)
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt1_p4 t2
+                                 ->  Seq Scan on plt1_p1 t2_1
+                                 ->  Seq Scan on plt1_p2 t2_2
+                                 ->  Seq Scan on plt1_p3 t2_3
+(22 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+(19 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(19 rows)
 
 -- joins where one of the relations is proven empty
 EXPLAIN (COSTS OFF)
@@ -1241,22 +4040,22 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
 --------------------------------------------------
  Hash Left Join
    Hash Cond: (t2.b = a)
-   ->  Append
-         ->  Hash Join
-               Hash Cond: (t3.a = t2.b)
-               ->  Seq Scan on prt1_p1 t3
-               ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
-         ->  Hash Join
-               Hash Cond: (t3_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t3_1
-               ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
-         ->  Hash Join
-               Hash Cond: (t3_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t3_2
-               ->  Hash
-                     ->  Seq Scan on prt2_p3 t2_2
+   ->  Hash Join
+         Hash Cond: (t3.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t3
+               ->  Seq Scan on prt1_p1 t3_1
+               ->  Seq Scan on prt1_p2 t3_2
+               ->  Seq Scan on prt1_p3 t3_3
+               ->  Seq Scan on prt1_p4 t3_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
    ->  Hash
          ->  Result
                One-Time Filter: false
@@ -1271,16 +4070,22 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
    ->  Hash Left Join
          Hash Cond: (t2.b = a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
+               ->  Seq Scan on prt2_p0 t2
                      Filter: (a = 0)
-               ->  Seq Scan on prt2_p2 t2_1
+               ->  Seq Scan on prt2_p1 t2_1
                      Filter: (a = 0)
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p2 t2_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t2_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t2_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t2_5
                      Filter: (a = 0)
          ->  Hash
                ->  Result
                      One-Time Filter: false
-(14 rows)
+(20 rows)
 
 --
 -- tests for hash partitioned tables.
@@ -1356,41 +4161,9 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, ph
  273.0000000000000000 | 273.0000000000000000 | 548.0000000000000000 | 0005 | 0005 | A0005
 (6 rows)
 
--- test default partition behavior for range
-ALTER TABLE prt1 DETACH PARTITION prt1_p3;
-ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
-ANALYZE prt1;
-ALTER TABLE prt2 DETACH PARTITION prt2_p3;
-ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
-ANALYZE prt2;
-EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-                    QUERY PLAN                    
---------------------------------------------------
- Sort
-   Sort Key: t1.a
-   ->  Append
-         ->  Hash Join
-               Hash Cond: (t2.b = t1.a)
-               ->  Seq Scan on prt2_p1 t2
-               ->  Hash
-                     ->  Seq Scan on prt1_p1 t1
-                           Filter: (b = 0)
-         ->  Hash Join
-               Hash Cond: (t2_1.b = t1_1.a)
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Hash
-                     ->  Seq Scan on prt1_p2 t1_1
-                           Filter: (b = 0)
-         ->  Hash Join
-               Hash Cond: (t2_2.b = t1_2.a)
-               ->  Seq Scan on prt2_p3 t2_2
-               ->  Hash
-                     ->  Seq Scan on prt1_p3 t1_2
-                           Filter: (b = 0)
-(21 rows)
-
--- test default partition behavior for list
+-- test default partition behavior for list, should not use partition-wise join
+-- since default partition from one side matches multiple partitions on the
+-- other
 ALTER TABLE plt1 DETACH PARTITION plt1_p3;
 ALTER TABLE plt1 ATTACH PARTITION plt1_p3 DEFAULT;
 ANALYZE plt1;
@@ -1405,26 +4178,24 @@ SELECT avg(t1.a), avg(t2.b), t1.c, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c
    Sort Key: t1.c
    ->  HashAggregate
          Group Key: t1.c, t2.c
-         ->  Append
-               ->  Hash Join
-                     Hash Cond: (t2.c = t1.c)
-                     ->  Seq Scan on plt2_p1 t2
-                     ->  Hash
-                           ->  Seq Scan on plt1_p1 t1
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+               ->  Hash
+                     ->  Append
+                           ->  Seq Scan on plt1_p4 t1
                                  Filter: ((a % 25) = 0)
-               ->  Hash Join
-                     Hash Cond: (t2_1.c = t1_1.c)
-                     ->  Seq Scan on plt2_p2 t2_1
-                     ->  Hash
-                           ->  Seq Scan on plt1_p2 t1_1
+                           ->  Seq Scan on plt1_p1 t1_1
                                  Filter: ((a % 25) = 0)
-               ->  Hash Join
-                     Hash Cond: (t2_2.c = t1_2.c)
-                     ->  Seq Scan on plt2_p3 t2_2
-                     ->  Hash
-                           ->  Seq Scan on plt1_p3 t1_2
+                           ->  Seq Scan on plt1_p2 t1_2
                                  Filter: ((a % 25) = 0)
-(23 rows)
+                           ->  Seq Scan on plt1_p3 t1_3
+                                 Filter: ((a % 25) = 0)
+(21 rows)
 
 --
 -- multiple levels of partitioning
@@ -1826,64 +4597,70 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a;
  Hash Join
    Hash Cond: (t1.a = t2.a)
    ->  Append
-         ->  Seq Scan on prt1_p1 t1
-         ->  Seq Scan on prt1_p2 t1_1
-         ->  Seq Scan on prt1_p3 t1_2
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
    ->  Hash
          ->  Append
                ->  Seq Scan on prt4_n_p1 t2
                ->  Seq Scan on prt4_n_p2 t2_1
                ->  Seq Scan on prt4_n_p3 t2_2
-(11 rows)
+(13 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2, prt2 t3 WHERE t1.a = t2.a and t1.a = t3.b;
-                       QUERY PLAN                       
---------------------------------------------------------
+                        QUERY PLAN                        
+----------------------------------------------------------
  Hash Join
-   Hash Cond: (t2.a = t1.a)
+   Hash Cond: (t3.b = t1.a)
    ->  Append
-         ->  Seq Scan on prt4_n_p1 t2
-         ->  Seq Scan on prt4_n_p2 t2_1
-         ->  Seq Scan on prt4_n_p3 t2_2
+         ->  Seq Scan on prt2_p0 t3
+         ->  Seq Scan on prt2_p1 t3_1
+         ->  Seq Scan on prt2_p2 t3_2
+         ->  Seq Scan on prt2_p3 t3_3
+         ->  Seq Scan on prt2_p4 t3_4
+         ->  Seq Scan on prt2_p5 t3_5
    ->  Hash
-         ->  Append
-               ->  Hash Join
-                     Hash Cond: (t1.a = t3.b)
-                     ->  Seq Scan on prt1_p1 t1
-                     ->  Hash
-                           ->  Seq Scan on prt2_p1 t3
-               ->  Hash Join
-                     Hash Cond: (t1_1.a = t3_1.b)
-                     ->  Seq Scan on prt1_p2 t1_1
-                     ->  Hash
-                           ->  Seq Scan on prt2_p2 t3_1
-               ->  Hash Join
-                     Hash Cond: (t1_2.a = t3_2.b)
-                     ->  Seq Scan on prt1_p3 t1_2
-                     ->  Hash
-                           ->  Seq Scan on prt2_p3 t3_2
+         ->  Hash Join
+               Hash Cond: (t1.a = t2.a)
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                     ->  Seq Scan on prt1_p1 t1_1
+                     ->  Seq Scan on prt1_p2 t1_2
+                     ->  Seq Scan on prt1_p3 t1_3
+                     ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Append
+                           ->  Seq Scan on prt4_n_p1 t2
+                           ->  Seq Scan on prt4_n_p2 t2_1
+                           ->  Seq Scan on prt4_n_p3 t2_2
 (23 rows)
 
 -- partitionwise 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                        
----------------------------------------------------------
+                 QUERY PLAN                 
+--------------------------------------------
  Nested Loop Left Join
+   Join Filter: (t1.a < t2.b)
    ->  Append
-         ->  Seq Scan on prt1_p1 t1
-         ->  Seq Scan on prt1_p2 t1_1
-         ->  Seq Scan on prt1_p3 t1_2
-   ->  Append
-         ->  Index Scan using iprt2_p1_b on prt2_p1 t2
-               Index Cond: (t1.a < b)
-         ->  Index Scan using iprt2_p2_b on prt2_p2 t2_1
-               Index Cond: (t1.a < b)
-         ->  Index Scan using iprt2_p3_b on prt2_p3 t2_2
-               Index Cond: (t1.a < b)
-(12 rows)
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+(16 rows)
 
 -- equi-join with join condition on partial keys does not qualify for
 -- partitionwise join
@@ -1969,16 +4746,17 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 JOIN prt2_n t2 ON (t1.c = t2.c) JOI
          ->  Seq Scan on prt2_n_p2 t2_1
    ->  Hash
          ->  Hash Join
-               Hash Cond: (t3.c = (t1.c)::text)
+               Hash Cond: ((t3.c)::text = (t1.c)::text)
                ->  Append
-                     ->  Seq Scan on plt1_p1 t3
-                     ->  Seq Scan on plt1_p2 t3_1
-                     ->  Seq Scan on plt1_p3 t3_2
+                     ->  Seq Scan on plt1_p4 t3
+                     ->  Seq Scan on plt1_p1 t3_1
+                     ->  Seq Scan on plt1_p2 t3_2
+                     ->  Seq Scan on plt1_p3 t3_3
                ->  Hash
                      ->  Append
                            ->  Seq Scan on prt1_n_p1 t1
                            ->  Seq Scan on prt1_n_p2 t1_1
-(16 rows)
+(17 rows)
 
 -- partitionwise join can not be applied for a join between list and range
 -- partitioned table
@@ -1989,14 +4767,16 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c);
  Hash Full Join
    Hash Cond: ((t2.c)::text = (t1.c)::text)
    ->  Append
-         ->  Seq Scan on prt1_p1 t2
-         ->  Seq Scan on prt1_p2 t2_1
-         ->  Seq Scan on prt1_p3 t2_2
+         ->  Seq Scan on prt1_p0 t2
+         ->  Seq Scan on prt1_p1 t2_1
+         ->  Seq Scan on prt1_p2 t2_2
+         ->  Seq Scan on prt1_p3 t2_3
+         ->  Seq Scan on prt1_p4 t2_4
    ->  Hash
          ->  Append
                ->  Seq Scan on prt1_n_p1 t1
                ->  Seq Scan on prt1_n_p2 t1_1
-(10 rows)
+(12 rows)
 
 -- partitionwise join can not be applied if only one of joining table has
 -- default partition
@@ -2012,16 +4792,23 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b =
    ->  Hash Join
          Hash Cond: (t2.b = t1.a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
          ->  Hash
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(16 rows)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
 
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index c1c9859651..0e884835fb 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -10,25 +10,39 @@ SET enable_partitionwise_join to true;
 -- partitioned by a single column
 --
 CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p0 PARTITION OF prt1 FOR VALUES FROM (MINVALUE) TO (0);
 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 % 25, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 2 = 0;
+CREATE TABLE prt1_p4 PARTITION OF prt1 FOR VALUES FROM (600) TO (800);
+INSERT INTO prt1 SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 2 = 0;
+CREATE INDEX iprt1_p0_a on prt1_p0(a);
 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 iprt1_p4_a on prt1_p4(a);
 ANALYZE prt1;
 
+-- prt2 have missing starting MINVALUE to -250 range and
+-- extra bounds from 800 to MAXVALUE
 CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p0 PARTITION OF prt2 FOR VALUES FROM (-250) TO (0);
 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 % 25, i, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 3 = 0;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (MAXVALUE);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 3 = 0;
+CREATE INDEX iprt2_p0_b on prt2_p0(b);
 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 iprt2_p4_b on prt2_p4(b);
 ANALYZE prt2;
 
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
+
 -- inner join
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
@@ -67,11 +81,19 @@ EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
 
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+
 -- Anti-join with aggregates
 EXPLAIN (COSTS OFF)
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
 
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+
 -- lateral reference
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
@@ -93,20 +115,30 @@ SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
 -- partitioned by expression
 --
 CREATE TABLE prt1_e (a int, b int, c int) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p0 PARTITION OF prt1_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt1_e_p4 PARTITION OF prt1_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(0, 599, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(600, 799, 2) i;
+CREATE INDEX iprt1_e_p0_ab2 on prt1_e_p1(((a+b)/2));
 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));
+CREATE INDEX iprt1_e_p4_ab2 on prt1_e_p1(((a+b)/2));
 ANALYZE prt1_e;
 
 CREATE TABLE prt2_e (a int, b int, c int) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p0 PARTITION OF prt2_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt2_e_p4 PARTITION OF prt2_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(0, 599, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(600, 799, 3) i;
 ANALYZE prt2_e;
 
 EXPLAIN (COSTS OFF)
@@ -169,6 +201,128 @@ SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.
 RESET enable_hashjoin;
 RESET enable_nestloop;
 
+-- test default partition behavior for range, partition-wise join is not
+-- possible since more than one partition on one side matches default partition
+-- on the other side. Default partition from prt1 matches default partition and
+-- prt2_p4 from prt2 and default partition from prt2 matches default partition
+-- and prt1_p0 from prt1
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+
+-- partition-wise join should be possible when we drop the first and last
+-- partitions from both sides
+ALTER TABLE prt1 DETACH PARTITION prt1_p0;
+ALTER TABLE prt1 DETACH PARTITION prt1_p4;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p0;
+ALTER TABLE prt2 DETACH PARTITION prt2_p4;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+
+-- restore the partitioned tables for rest of the tests
+ALTER TABLE prt1 ATTACH PARTITION prt1_p0 FOR VALUES FROM (MINVALUE) TO (0);
+ALTER TABLE prt1 ATTACH PARTITION prt1_p4 FOR VALUES FROM (600) TO (800);
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt1;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p0 FOR VALUES FROM (-250) TO (0);
+ALTER TABLE prt2 ATTACH PARTITION prt2_p4 FOR VALUES FROM (600) TO (MAXVALUE);
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt2;
+
+-- Add an extra partition to prt2 , Partition-wise join is possible with
+-- extra partitions on inner side are allowed
+DROP TABLE prt2_p4;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (800);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (800) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999) i WHERE i % 3 = 0;
+ANALYZE prt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- 3-way join when not every pair of joining relation can use partition-wise
+-- join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+
+-- partition-wise join can not handle missing partition on the inner side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.b;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE coalesce(t1.b, 0) + coalesce(t2.a, 0) = 0 ORDER BY t1.a, t2.a;
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE prt2_p4;
+DROP TABLE prt2_p5;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (700);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (700) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999, 3) i;
+ANALYZE prt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b + t2.a = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
 --
 -- partitioned by multiple columns
 --
@@ -193,28 +347,79 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1
 --
 -- 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;
+\set part_mod 17
+\set cond_mod 47
+\set num_rows 500
+
+CREATE TABLE plt1 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0001','0002','0003');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0008','0009');
+CREATE TABLE plt1_p4 PARTITION OF plt1 FOR VALUES IN ('0000','0010');
+INSERT INTO plt1 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (7, 11, 12, 13, 14, 15, 16);
+ANALYSE plt1;
+
+-- plt2 have missing starting 0001, additional 0007, missing ending 0010
+-- and additional 0011 and 0012 bounds
+CREATE TABLE plt2 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0002','0003');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0007','0008','0009');
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000','0011','0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 10, 13, 14, 15, 16);
+ANALYSE plt2;
+
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
 
-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;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
 
 --
 -- 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;
+CREATE TABLE plt1_e_p1 PARTITION OF plt1_e FOR VALUES IN ('0002', '0003');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0004', '0005', '0006');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0008', '0009');
+CREATE TABLE plt1_e_p4 PARTITION OF plt1_e FOR VALUES IN ('0000');
+INSERT INTO plt1_e SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 7, 10, 11, 12, 13, 14, 15, 16);
 ANALYZE plt1_e;
 
 -- test partition matching with N-way join
@@ -222,6 +427,175 @@ EXPLAIN (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.b = t2.b AND 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.b = t2.b AND 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;
 
+-- Add an extra partition to plt2 , Partition-wise join is possible with
+-- partitions on inner side are allowed
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (13, 14);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt2_p5;
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0001','0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (1, 13, 14);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- partition have a NULL on one side, Partition-wise join is possible with
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- in this case NULL will be treated as addition partition bounds.
+DROP TABLE plt2_p5;
+DROP TABLE plt2_p4;
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000',NULL,'0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, case when i % :part_mod = 11 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (0,11,12);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- partition have a NULL on both side with different partition bounds w.r.t other side
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt1_p3;
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN (NULL,'0008','0009');
+INSERT INTO plt1 SELECT i, i % :cond_mod, case when i % :part_mod = 7 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (7,8,9);
+ANALYZE plt1;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
 -- joins where one of the relations is proven empty
 EXPLAIN (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;
@@ -267,27 +641,18 @@ EXPLAIN (COSTS OFF)
 SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND 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 pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND 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;
 
--- test default partition behavior for range
-ALTER TABLE prt1 DETACH PARTITION prt1_p3;
-ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
-ANALYZE prt1;
-ALTER TABLE prt2 DETACH PARTITION prt2_p3;
-ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
-ANALYZE prt2;
-
-EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-
--- test default partition behavior for list
+-- test default partition behavior for list, should not use partition-wise join
+-- since default partition from one side matches multiple partitions on the
+-- other
 ALTER TABLE plt1 DETACH PARTITION plt1_p3;
 ALTER TABLE plt1 ATTACH PARTITION plt1_p3 DEFAULT;
 ANALYZE plt1;
 ALTER TABLE plt2 DETACH PARTITION plt2_p3;
 ALTER TABLE plt2 ATTACH PARTITION plt2_p3 DEFAULT;
 ANALYZE plt2;
-
 EXPLAIN (COSTS OFF)
 SELECT avg(t1.a), avg(t2.b), t1.c, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.a % 25 = 0 GROUP BY t1.c, t2.c ORDER BY t1.c, t2.c;
+
 --
 -- multiple levels of partitioning
 --
-- 
2.19.2


--------------010102020204050006020806--





^ permalink  raw  reply  [nested|flat] 6+ messages in thread

* [PATCH 3/3] Tests for 0:1, 1:1 and 1:0 partition matching
@ 2019-01-31 11:31 Etsuro Fujita <[email protected]>
  0 siblings, 0 replies; 6+ messages in thread

From: Etsuro Fujita @ 2019-01-31 11:31 UTC (permalink / raw)

Rajkumar Raghuvanshi and Ashutosh Bapat.
---
 src/test/regress/expected/partition_join.out | 4131 +++++++++++++++---
 src/test/regress/sql/partition_join.sql      |  427 +-
 2 files changed, 3855 insertions(+), 703 deletions(-)

diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index c55de5d476..f19611c853 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -8,59 +8,86 @@ SET enable_partitionwise_join to true;
 -- partitioned by a single column
 --
 CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p0 PARTITION OF prt1 FOR VALUES FROM (MINVALUE) TO (0);
 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 % 25, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 2 = 0;
+CREATE TABLE prt1_p4 PARTITION OF prt1 FOR VALUES FROM (600) TO (800);
+INSERT INTO prt1 SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 2 = 0;
+CREATE INDEX iprt1_p0_a on prt1_p0(a);
 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 iprt1_p4_a on prt1_p4(a);
 ANALYZE prt1;
+-- prt2 have missing starting MINVALUE to -250 range and
+-- extra bounds from 800 to MAXVALUE
 CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p0 PARTITION OF prt2 FOR VALUES FROM (-250) TO (0);
 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 % 25, i, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 3 = 0;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (MAXVALUE);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 3 = 0;
+CREATE INDEX iprt2_p0_b on prt2_p0(b);
 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 iprt2_p4_b on prt2_p4(b);
 ANALYZE prt2;
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
 -- inner join
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-                    QUERY PLAN                    
---------------------------------------------------
+                          QUERY PLAN                           
+---------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Hash Join
                Hash Cond: (t2.b = t1.a)
-               ->  Seq Scan on prt2_p1 t2
+               ->  Seq Scan on prt2_p0 t2
                ->  Hash
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
          ->  Hash Join
                Hash Cond: (t2_1.b = t1_1.a)
-               ->  Seq Scan on prt2_p2 t2_1
+               ->  Seq Scan on prt2_p1 t2_1
                ->  Hash
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
          ->  Hash Join
                Hash Cond: (t2_2.b = t1_2.a)
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p2 t2_2
                ->  Hash
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(21 rows)
+         ->  Nested Loop
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 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)
+  a   |   c   |  b   |   c   
+------+-------+------+-------
+ -150 | -0150 | -150 | -0150
+    0 | 0000  |    0 | 0000
+  150 | 0150  |  150 | 0150
+  300 | 0300  |  300 | 0300
+  450 | 0450  |  450 | 0450
+  600 | 0600  |  600 | 0600
+  750 | 0750  |  750 | 0750
+(7 rows)
 
 -- left outer join, with whole-row reference; partitionwise join does not apply
 EXPLAIN (COSTS OFF)
@@ -72,35 +99,50 @@ SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER
    ->  Hash Right Join
          Hash Cond: (t2.b = t1.a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
          ->  Hash
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(16 rows)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(22 rows)
 
 SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
-      t1      |      t2      
---------------+--------------
- (0,0,0000)   | (0,0,0000)
- (50,0,0050)  | 
- (100,0,0100) | 
- (150,0,0150) | (0,150,0150)
- (200,0,0200) | 
- (250,0,0250) | 
- (300,0,0300) | (0,300,0300)
- (350,0,0350) | 
- (400,0,0400) | 
- (450,0,0450) | (0,450,0450)
- (500,0,0500) | 
- (550,0,0550) | 
-(12 rows)
+       t1       |       t2       
+----------------+----------------
+ (-250,0,-0250) | 
+ (-200,0,-0200) | 
+ (-150,0,-0150) | (0,-150,-0150)
+ (-100,0,-0100) | 
+ (-50,0,-0050)  | 
+ (0,0,0000)     | (0,0,0000)
+ (50,0,0050)    | 
+ (100,0,0100)   | 
+ (150,0,0150)   | (0,150,0150)
+ (200,0,0200)   | 
+ (250,0,0250)   | 
+ (300,0,0300)   | (0,300,0300)
+ (350,0,0350)   | 
+ (400,0,0400)   | 
+ (450,0,0450)   | (0,450,0450)
+ (500,0,0500)   | 
+ (550,0,0550)   | 
+ (600,0,0600)   | (0,600,0600)
+ (650,0,0650)   | 
+ (700,0,0700)   | 
+ (750,0,0750)   | (0,750,0750)
+(21 rows)
 
 -- right outer join
 EXPLAIN (COSTS OFF)
@@ -112,35 +154,53 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHE
    ->  Append
          ->  Hash Right Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
                            Filter: (a = 0)
          ->  Hash Right Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+                           Filter: (a = 0)
+         ->  Hash Right Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
                            Filter: (a = 0)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
                      Filter: (a = 0)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
-                     Index Cond: (a = t2_2.b)
-(20 rows)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+(32 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 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)
+  a   |   c   |  b   |   c   
+------+-------+------+-------
+ -150 | -0150 | -150 | -0150
+    0 | 0000  |    0 | 0000
+  150 | 0150  |  150 | 0150
+  300 | 0300  |  300 | 0300
+  450 | 0450  |  450 | 0450
+  600 | 0600  |  600 | 0600
+  750 | 0750  |  750 | 0750
+      |       | -225 | -0225
+      |       |  -75 | -0075
+      |       |   75 | 0075
+      |       |  225 | 0225
+      |       |  375 | 0375
+      |       |  525 | 0525
+      |       |  675 | 0675
+(14 rows)
 
 -- full outer join, with placeholder vars
 EXPLAIN (COSTS OFF)
@@ -148,8 +208,16 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0)
                             QUERY PLAN                            
 ------------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, prt2_p1.b
+   Sort Key: prt1_p0.a, prt2_p0.b
    ->  Append
+         ->  Hash Full Join
+               Hash Cond: (prt1_p0.a = prt2_p0.b)
+               Filter: (((50) = prt1_p0.a) OR ((75) = prt2_p0.b))
+               ->  Seq Scan on prt1_p0
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0
+                           Filter: (a = 0)
          ->  Hash Full Join
                Hash Cond: (prt1_p1.a = prt2_p1.b)
                Filter: (((50) = prt1_p1.a) OR ((75) = prt2_p1.b))
@@ -174,7 +242,15 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0)
                ->  Hash
                      ->  Seq Scan on prt2_p3
                            Filter: (a = 0)
-(27 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt1_p4.a = prt2_p4.b)
+               Filter: (((50) = prt1_p4.a) OR ((75) = prt2_p4.b))
+               ->  Seq Scan on prt1_p4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4
+                           Filter: (a = 0)
+(43 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b;
  a  |  c   | b  |  c   
@@ -211,8 +287,15 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO
                         QUERY PLAN                         
 -----------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Hash Left Join
+               Hash Cond: (prt1_p0.a = b)
+               ->  Seq Scan on prt1_p0
+                     Filter: ((a < 450) AND (b = 0))
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
          ->  Hash Left Join
                Hash Cond: (prt1_p1.a = b)
                ->  Seq Scan on prt1_p1
@@ -227,29 +310,42 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO
                ->  Hash
                      ->  Seq Scan on prt1_p2
                            Filter: ((a < 450) AND (b = 0))
-(17 rows)
+(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.b = 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)
+  a   |   c   |  b  |  c   
+------+-------+-----+------
+ -250 | -0250 |     | 
+ -200 | -0200 |     | 
+ -150 | -0150 |     | 
+ -100 | -0100 |     | 
+  -50 | -0050 |     | 
+    0 | 0000  |     | 
+   50 | 0050  |     | 
+  100 | 0100  |     | 
+  150 | 0150  |     | 
+  200 | 0200  |     | 
+  250 | 0250  |     | 
+  300 | 0300  | 300 | 0300
+  350 | 0350  |     | 
+  400 | 0400  |     | 
+(14 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 0 ORDER BY t1.a, t2.b;
                          QUERY PLAN                         
 ------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Hash Full Join
+               Hash Cond: (prt1_p0.a = b)
+               Filter: ((prt1_p0.b = 0) OR (a = 0))
+               ->  Seq Scan on prt1_p0
+                     Filter: (a < 450)
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
          ->  Hash Full Join
                Hash Cond: (prt1_p1.a = b)
                Filter: ((prt1_p1.b = 0) OR (a = 0))
@@ -274,64 +370,153 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO
                ->  Hash
                      ->  Result
                            One-Time Filter: false
-(27 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt2_p4.b = a)
+               Filter: ((b = 0) OR (prt2_p4.a = 0))
+               ->  Seq Scan on prt2_p4
+                     Filter: (b > 250)
+               ->  Hash
+                     ->  Result
+                           One-Time Filter: false
+(43 rows)
 
 SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 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 |     | 
-     |      | 375 | 0375
-     |      | 450 | 0450
-     |      | 525 | 0525
-(12 rows)
+  a   |   c   |  b  |  c   
+------+-------+-----+------
+ -250 | -0250 |     | 
+ -200 | -0200 |     | 
+ -150 | -0150 |     | 
+ -100 | -0100 |     | 
+  -50 | -0050 |     | 
+    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
+      |       | 600 | 0600
+      |       | 675 | 0675
+      |       | 750 | 0750
+(20 rows)
 
 -- Semi-join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
-                    QUERY PLAN                    
---------------------------------------------------
+                          QUERY PLAN                           
+---------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Hash Semi Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
                            Filter: (a = 0)
          ->  Hash Semi Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
                            Filter: (a = 0)
-         ->  Nested Loop Semi Join
-               Join Filter: (t1_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t1_2
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
-               ->  Materialize
-                     ->  Seq Scan on prt2_p3 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
                            Filter: (a = 0)
-(24 rows)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t2_3.b
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+                     Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+(39 rows)
 
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b
+   ->  Append
+         ->  Hash Semi Join
+               Hash Cond: (t1.b = t2.a)
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t2
+                           Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_1.b = t2_1.a)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t2_1
+                           Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.b = t2_2.a)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t2_2
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: (t1_3.b = t2_3.a)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt1_p3 t2_3
+                     Filter: (b = 0)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.b = t2_4.a)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t2_4
+                           Filter: (b = 0)
+(37 rows)
+
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+ a |  b   |   c   
+---+------+-------
+ 0 | -150 | -0150
+ 0 |    0 | 0000
+ 0 |  150 | 0150
+ 0 |  300 | 0300
+ 0 |  450 | 0450
+ 0 |  600 | 0600
+ 0 |  750 | 0750
+(7 rows)
 
 -- Anti-join with aggregates
 EXPLAIN (COSTS OFF)
@@ -342,27 +527,82 @@ SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS
    ->  Append
          ->  Hash Anti Join
                Hash Cond: (t1.a = t2.b)
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
          ->  Hash Anti Join
                Hash Cond: (t1_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
          ->  Hash Anti Join
                Hash Cond: (t1_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                ->  Hash
-                     ->  Seq Scan on prt2_p3 t2_2
-(17 rows)
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Hash Anti Join
+               Hash Cond: (t1_3.a = t2_3.b)
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on prt2_p3 t2_3
+         ->  Hash Anti Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(27 rows)
 
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
-  sum  |         avg          | sum  |         avg         
--------+----------------------+------+---------------------
- 60000 | 300.0000000000000000 | 2400 | 12.0000000000000000
+  sum  |         avg          | sum  |        avg         
+-------+----------------------+------+--------------------
+ 95550 | 273.0000000000000000 | 2200 | 6.2857142857142857
 (1 row)
 
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Append
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p0 t1
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
+               Index Cond: (a = t1.b)
+   ->  Hash Anti Join
+         Hash Cond: (t1_1.b = t2_1.a)
+         ->  Seq Scan on prt2_p1 t1_1
+               Filter: (a = 0)
+         ->  Hash
+               ->  Seq Scan on prt1_p1 t2_1
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p2 t1_2
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
+               Index Cond: (a = t1_2.b)
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p3 t1_3
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+               Index Cond: (a = t1_3.b)
+   ->  Nested Loop Anti Join
+         ->  Seq Scan on prt2_p4 t1_4
+               Filter: (a = 0)
+         ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+               Index Cond: (a = t1_4.b)
+(27 rows)
+
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+  b   |   c   
+------+-------
+ -225 | -0225
+  -75 | -0075
+   75 | 0075
+  225 | 0225
+  375 | 0375
+  525 | 0525
+  675 | 0675
+(7 rows)
+
 -- lateral reference
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
@@ -374,49 +614,74 @@ SELECT * FROM prt1 t1 LEFT JOIN LATERAL
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2
+                     ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
                            Index Cond: (a = t1.a)
-                     ->  Index Scan using iprt2_p1_b on prt2_p1 t3
+                     ->  Index Scan using iprt2_p0_b on prt2_p0 t3
                            Index Cond: (b = t2.a)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_1
+                     ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2_1
                            Index Cond: (a = t1_1.a)
-                     ->  Index Scan using iprt2_p2_b on prt2_p2 t3_1
+                     ->  Index Scan using iprt2_p1_b on prt2_p1 t3_1
                            Index Cond: (b = t2_1.a)
          ->  Nested Loop Left Join
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
                ->  Nested Loop
-                     ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_2
+                     ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
                            Index Cond: (a = t1_2.a)
-                     ->  Index Scan using iprt2_p3_b on prt2_p3 t3_2
+                     ->  Index Scan using iprt2_p2_b on prt2_p2 t3_2
                            Index Cond: (b = t2_2.a)
-(27 rows)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Nested Loop
+                     ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+                           Index Cond: (a = t1_3.a)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t3_3
+                           Index Cond: (b = t2_3.a)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Nested Loop
+                     ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+                           Index Cond: (a = t1_4.a)
+                     ->  Index Scan using iprt2_p4_b on prt2_p4 t3_4
+                           Index Cond: (b = t2_4.a)
+(43 rows)
 
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
 			  (SELECT t2.a AS t2a, t3.a AS t3a, least(t1.a,t2.a,t3.b) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
 			  ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   | t2a | t3a | least 
------+---+------+-----+-----+-------
-   0 | 0 | 0000 |   0 |   0 |     0
-  50 | 0 | 0050 |     |     |      
- 100 | 0 | 0100 |     |     |      
- 150 | 0 | 0150 | 150 |   0 |   150
- 200 | 0 | 0200 |     |     |      
- 250 | 0 | 0250 |     |     |      
- 300 | 0 | 0300 | 300 |   0 |   300
- 350 | 0 | 0350 |     |     |      
- 400 | 0 | 0400 |     |     |      
- 450 | 0 | 0450 | 450 |   0 |   450
- 500 | 0 | 0500 |     |     |      
- 550 | 0 | 0550 |     |     |      
-(12 rows)
+  a   | b |   c   | t2a  | t3a | least 
+------+---+-------+------+-----+-------
+ -250 | 0 | -0250 |      |     |      
+ -200 | 0 | -0200 |      |     |      
+ -150 | 0 | -0150 | -150 |   0 |  -150
+ -100 | 0 | -0100 |      |     |      
+  -50 | 0 | -0050 |      |     |      
+    0 | 0 | 0000  |    0 |   0 |     0
+   50 | 0 | 0050  |      |     |      
+  100 | 0 | 0100  |      |     |      
+  150 | 0 | 0150  |  150 |   0 |   150
+  200 | 0 | 0200  |      |     |      
+  250 | 0 | 0250  |      |     |      
+  300 | 0 | 0300  |  300 |   0 |   300
+  350 | 0 | 0350  |      |     |      
+  400 | 0 | 0400  |      |     |      
+  450 | 0 | 0450  |  450 |   0 |   450
+  500 | 0 | 0500  |      |     |      
+  550 | 0 | 0550  |      |     |      
+  600 | 0 | 0600  |  600 |   0 |   600
+  650 | 0 | 0650  |      |     |      
+  700 | 0 | 0700  |      |     |      
+  750 | 0 | 0750  |  750 |   0 |   750
+(21 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
@@ -430,64 +695,95 @@ SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
          Hash Cond: ((t1.c)::text = (t2.c)::text)
          Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
          ->  Append
-               ->  Seq Scan on prt1_p1 t1
-               ->  Seq Scan on prt1_p2 t1_1
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
          ->  Hash
                ->  Append
                      ->  Hash Join
                            Hash Cond: (t2.a = t3.b)
-                           ->  Seq Scan on prt1_p1 t2
+                           ->  Seq Scan on prt1_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p1 t3
+                                 ->  Seq Scan on prt2_p0 t3
                      ->  Hash Join
                            Hash Cond: (t2_1.a = t3_1.b)
-                           ->  Seq Scan on prt1_p2 t2_1
+                           ->  Seq Scan on prt1_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt2_p2 t3_1
+                                 ->  Seq Scan on prt2_p1 t3_1
                      ->  Hash Join
                            Hash Cond: (t2_2.a = t3_2.b)
-                           ->  Seq Scan on prt1_p3 t2_2
+                           ->  Seq Scan on prt1_p2 t2_2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p3 t3_2
-(26 rows)
+                                 ->  Seq Scan on prt2_p2 t3_2
+                     ->  Hash Join
+                           Hash Cond: (t2_3.a = t3_3.b)
+                           ->  Seq Scan on prt1_p3 t2_3
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p3 t3_3
+                     ->  Hash Join
+                           Hash Cond: (t2_4.a = t3_4.b)
+                           ->  Seq Scan on prt1_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t3_4
+(38 rows)
 
 SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
 			  (SELECT t2.a AS t2a, t3.a AS t3a, t2.b t2b, t2.c t2c, least(t1.a,t2.a,t3.a) FROM prt1 t2 JOIN prt2 t3 ON (t2.a = t3.b)) ss
 			  ON t1.c = ss.t2c WHERE (t1.b + coalesce(ss.t2b, 0)) = 0 ORDER BY t1.a;
-  a  | t2a | t2c  
------+-----+------
-   0 |   0 | 0000
-  50 |     | 
- 100 |     | 
- 150 | 150 | 0150
- 200 |     | 
- 250 |     | 
- 300 | 300 | 0300
- 350 |     | 
- 400 |     | 
- 450 | 450 | 0450
- 500 |     | 
- 550 |     | 
-(12 rows)
+  a   | t2a  |  t2c  
+------+------+-------
+ -250 |      | 
+ -200 |      | 
+ -150 | -150 | -0150
+ -100 |      | 
+  -50 |      | 
+    0 |    0 | 0000
+   50 |      | 
+  100 |      | 
+  150 |  150 | 0150
+  200 |      | 
+  250 |      | 
+  300 |  300 | 0300
+  350 |      | 
+  400 |      | 
+  450 |  450 | 0450
+  500 |      | 
+  550 |      | 
+  600 |  600 | 0600
+  650 |      | 
+  700 |      | 
+  750 |  750 | 0750
+(21 rows)
 
 --
 -- partitioned by expression
 --
 CREATE TABLE prt1_e (a int, b int, c int) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p0 PARTITION OF prt1_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt1_e_p4 PARTITION OF prt1_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(0, 599, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(600, 799, 2) i;
+CREATE INDEX iprt1_e_p0_ab2 on prt1_e_p1(((a+b)/2));
 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));
+CREATE INDEX iprt1_e_p4_ab2 on prt1_e_p1(((a+b)/2));
 ANALYZE prt1_e;
 CREATE TABLE prt2_e (a int, b int, c int) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p0 PARTITION OF prt2_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt2_e_p4 PARTITION OF prt2_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(0, 599, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(600, 799, 3) i;
 ANALYZE prt2_e;
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b;
@@ -498,32 +794,49 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_e t1, prt2_e t2 WHERE (t1.a + t1.b)/2 =
    ->  Append
          ->  Hash Join
                Hash Cond: (((t2.b + t2.a) / 2) = ((t1.a + t1.b) / 2))
-               ->  Seq Scan on prt2_e_p1 t2
+               ->  Seq Scan on prt2_e_p0 t2
                ->  Hash
-                     ->  Seq Scan on prt1_e_p1 t1
+                     ->  Seq Scan on prt1_e_p0 t1
                            Filter: (c = 0)
          ->  Hash Join
-               Hash Cond: (((t2_1.b + t2_1.a) / 2) = ((t1_1.a + t1_1.b) / 2))
-               ->  Seq Scan on prt2_e_p2 t2_1
+               Hash Cond: (((t1_1.a + t1_1.b) / 2) = ((t2_1.b + t2_1.a) / 2))
+               ->  Seq Scan on prt1_e_p1 t1_1
+                     Filter: (c = 0)
                ->  Hash
-                     ->  Seq Scan on prt1_e_p2 t1_1
-                           Filter: (c = 0)
+                     ->  Seq Scan on prt2_e_p1 t2_1
          ->  Hash Join
                Hash Cond: (((t2_2.b + t2_2.a) / 2) = ((t1_2.a + t1_2.b) / 2))
-               ->  Seq Scan on prt2_e_p3 t2_2
+               ->  Seq Scan on prt2_e_p2 t2_2
                ->  Hash
-                     ->  Seq Scan on prt1_e_p3 t1_2
+                     ->  Seq Scan on prt1_e_p2 t1_2
                            Filter: (c = 0)
-(21 rows)
+         ->  Hash Join
+               Hash Cond: (((t2_3.b + t2_3.a) / 2) = ((t1_3.a + t1_3.b) / 2))
+               ->  Seq Scan on prt2_e_p3 t2_3
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p3 t1_3
+                           Filter: (c = 0)
+         ->  Hash Join
+               Hash Cond: (((t2_4.b + t2_4.a) / 2) = ((t1_4.a + t1_4.b) / 2))
+               ->  Seq Scan on prt2_e_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p4 t1_4
+                           Filter: (c = 0)
+(33 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.c = 0 ORDER BY t1.a, t2.b;
-  a  | c |  b  | c 
------+---+-----+---
-   0 | 0 |   0 | 0
- 150 | 0 | 150 | 0
- 300 | 0 | 300 | 0
- 450 | 0 | 450 | 0
-(4 rows)
+  a   | c |  b   | c 
+------+---+------+---
+ -250 | 0 | -250 | 0
+ -100 | 0 | -100 | 0
+    0 | 0 |    0 | 0
+    0 | 0 |    0 | 0
+  150 | 0 |  150 | 0
+  300 | 0 |  300 | 0
+  450 | 0 |  450 | 0
+  600 | 0 |  600 | 0
+  750 | 0 |  750 | 0
+(9 rows)
 
 --
 -- N-way join
@@ -536,154 +849,232 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
-               Join Filter: (t1.a = ((t3.a + t3.b) / 2))
+               Join Filter: (t1.a = t2.b)
                ->  Hash Join
-                     Hash Cond: (t2.b = t1.a)
-                     ->  Seq Scan on prt2_p1 t2
+                     Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
+                     ->  Seq Scan on prt1_e_p0 t3
                      ->  Hash
-                           ->  Seq Scan on prt1_p1 t1
+                           ->  Seq Scan on prt1_p0 t1
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p1_ab2 on prt1_e_p1 t3
-                     Index Cond: (((a + b) / 2) = t2.b)
+               ->  Index Scan using iprt2_p0_b on prt2_p0 t2
+                     Index Cond: (b = ((t3.a + t3.b) / 2))
          ->  Nested Loop
                Join Filter: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
                ->  Hash Join
                      Hash Cond: (t2_1.b = t1_1.a)
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
                      ->  Hash
-                           ->  Seq Scan on prt1_p2 t1_1
+                           ->  Seq Scan on prt1_p1 t1_1
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_1
+               ->  Index Scan using iprt1_e_p4_ab2 on prt1_e_p1 t3_1
                      Index Cond: (((a + b) / 2) = t2_1.b)
          ->  Nested Loop
                Join Filter: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
                ->  Hash Join
                      Hash Cond: (t2_2.b = t1_2.a)
-                     ->  Seq Scan on prt2_p3 t2_2
+                     ->  Seq Scan on prt2_p2 t2_2
                      ->  Hash
-                           ->  Seq Scan on prt1_p3 t1_2
+                           ->  Seq Scan on prt1_p2 t1_2
                                  Filter: (b = 0)
-               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_2
+               ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_2
                      Index Cond: (((a + b) / 2) = t2_2.b)
-(33 rows)
+         ->  Nested Loop
+               Join Filter: (t1_3.a = ((t3_3.a + t3_3.b) / 2))
+               ->  Nested Loop
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                           Index Cond: (b = t1_3.a)
+               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_3
+                     Index Cond: (((a + b) / 2) = t2_3.b)
+         ->  Nested Loop
+               Join Filter: (t1_4.a = t2_4.b)
+               ->  Hash Join
+                     Hash Cond: (((t3_4.a + t3_4.b) / 2) = t1_4.a)
+                     ->  Seq Scan on prt1_e_p4 t3_4
+                     ->  Hash
+                           ->  Seq Scan on prt1_p4 t1_4
+                                 Filter: (b = 0)
+               ->  Index Scan using iprt2_p4_b on prt2_p4 t2_4
+                     Index Cond: (b = ((t3_4.a + t3_4.b) / 2))
+(52 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.b = 0 ORDER BY t1.a, t2.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
-(4 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(8 rows)
 
 EXPLAIN (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.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-                          QUERY PLAN                          
---------------------------------------------------------------
+                             QUERY PLAN                              
+---------------------------------------------------------------------
  Sort
    Sort Key: t1.a, t2.b, ((t3.a + t3.b))
    ->  Append
          ->  Hash Right Join
                Hash Cond: (((t3.a + t3.b) / 2) = t1.a)
-               ->  Seq Scan on prt1_e_p1 t3
+               ->  Seq Scan on prt1_e_p0 t3
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2.b = t1.a)
-                           ->  Seq Scan on prt2_p1 t2
+                           ->  Seq Scan on prt2_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt1_p1 t1
+                                 ->  Seq Scan on prt1_p0 t1
                                        Filter: (b = 0)
          ->  Hash Right Join
                Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a)
-               ->  Seq Scan on prt1_e_p2 t3_1
+               ->  Seq Scan on prt1_e_p1 t3_1
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2_1.b = t1_1.a)
-                           ->  Seq Scan on prt2_p2 t2_1
+                           ->  Seq Scan on prt2_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt1_p2 t1_1
+                                 ->  Seq Scan on prt1_p1 t1_1
                                        Filter: (b = 0)
          ->  Hash Right Join
                Hash Cond: (((t3_2.a + t3_2.b) / 2) = t1_2.a)
-               ->  Seq Scan on prt1_e_p3 t3_2
+               ->  Seq Scan on prt1_e_p2 t3_2
                ->  Hash
                      ->  Hash Right Join
                            Hash Cond: (t2_2.b = t1_2.a)
-                           ->  Seq Scan on prt2_p3 t2_2
+                           ->  Seq Scan on prt2_p2 t2_2
                            ->  Hash
-                                 ->  Seq Scan on prt1_p3 t1_2
+                                 ->  Seq Scan on prt1_p2 t1_2
                                        Filter: (b = 0)
-(33 rows)
+         ->  Nested Loop Left Join
+               ->  Nested Loop Left Join
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                           Index Cond: (t1_3.a = b)
+               ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_3
+                     Index Cond: (t1_3.a = ((a + b) / 2))
+         ->  Hash Right Join
+               Hash Cond: (((t3_4.a + t3_4.b) / 2) = t1_4.a)
+               ->  Seq Scan on prt1_e_p4 t3_4
+               ->  Hash
+                     ->  Hash Right Join
+                           Hash Cond: (t2_4.b = t1_4.a)
+                           ->  Seq Scan on prt2_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt1_p4 t1_4
+                                       Filter: (b = 0)
+(51 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.b = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-                            QUERY PLAN                             
--------------------------------------------------------------------
+                             QUERY PLAN                              
+---------------------------------------------------------------------
  Sort
    Sort Key: t1.a, t2.b, ((t3.a + t3.b))
    ->  Append
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1.a = ((t3.a + t3.b) / 2))
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p1 t3
+                           ->  Seq Scan on prt1_e_p0 t3
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p1_b on prt2_p1 t2
+               ->  Index Scan using iprt2_p0_b on prt2_p0 t2
                      Index Cond: (t1.a = b)
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p2 t3_1
+                           ->  Seq Scan on prt1_e_p1 t3_1
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p2_b on prt2_p2 t2_1
+               ->  Index Scan using iprt2_p1_b on prt2_p1 t2_1
                      Index Cond: (t1_1.a = b)
          ->  Nested Loop Left Join
                ->  Hash Right Join
                      Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                      ->  Hash
-                           ->  Seq Scan on prt1_e_p3 t3_2
+                           ->  Seq Scan on prt1_e_p2 t3_2
                                  Filter: (c = 0)
-               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_2
+               ->  Index Scan using iprt2_p2_b on prt2_p2 t2_2
                      Index Cond: (t1_2.a = b)
-(30 rows)
+         ->  Nested Loop Left Join
+               ->  Nested Loop Left Join
+                     ->  Seq Scan on prt1_e_p3 t3_3
+                           Filter: (c = 0)
+                     ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                           Index Cond: (a = ((t3_3.a + t3_3.b) / 2))
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (t1_3.a = b)
+         ->  Nested Loop Left Join
+               ->  Hash Right Join
+                     Hash Cond: (t1_4.a = ((t3_4.a + t3_4.b) / 2))
+                     ->  Seq Scan on prt1_p4 t1_4
+                     ->  Hash
+                           ->  Seq Scan on prt1_e_p4 t3_4
+                                 Filter: (c = 0)
+               ->  Index Scan using iprt2_p4_b on prt2_p4 t2_4
+                     Index Cond: (t1_4.a = b)
+(47 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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 -- Cases with non-nullable expressions in subquery results;
 -- make sure these go to null as expected
@@ -692,21 +1083,34 @@ SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * F
                                                    QUERY PLAN                                                   
 ----------------------------------------------------------------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, prt2_p1.b, ((prt1_e_p1.a + prt1_e_p1.b))
+   Sort Key: prt1_p0.a, prt2_p0.b, ((prt1_e_p0.a + prt1_e_p0.b))
    ->  Append
          ->  Hash Full Join
-               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 Cond: (prt1_p0.a = ((prt1_e_p0.a + prt1_e_p0.b) / 2))
+               Filter: ((prt1_p0.a = (50)) OR (prt2_p0.b = (75)) OR (((prt1_e_p0.a + prt1_e_p0.b) / 2) = (50)))
                ->  Hash Full Join
-                     Hash Cond: (prt1_p1.a = prt2_p1.b)
-                     ->  Seq Scan on prt1_p1
+                     Hash Cond: (prt1_p0.a = prt2_p0.b)
+                     ->  Seq Scan on prt1_p0
                            Filter: (b = 0)
                      ->  Hash
-                           ->  Seq Scan on prt2_p1
+                           ->  Seq Scan on prt2_p0
                                  Filter: (a = 0)
                ->  Hash
-                     ->  Seq Scan on prt1_e_p1
+                     ->  Seq Scan on prt1_e_p0
                            Filter: (c = 0)
+         ->  Hash Full Join
+               Hash Cond: (((prt1_e_p1.a + prt1_e_p1.b) / 2) = prt1_p1.a)
+               Filter: ((prt1_p1.a = (50)) OR (prt2_p1.b = (75)) OR (((prt1_e_p1.a + prt1_e_p1.b) / 2) = (50)))
+               ->  Seq Scan on prt1_e_p1
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Hash Full Join
+                           Hash Cond: (prt1_p1.a = prt2_p1.b)
+                           ->  Seq Scan on prt1_p1
+                                 Filter: (b = 0)
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p1
+                                       Filter: (a = 0)
          ->  Hash Full Join
                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)))
@@ -733,7 +1137,20 @@ SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * F
                ->  Hash
                      ->  Seq Scan on prt1_e_p3
                            Filter: (c = 0)
-(42 rows)
+         ->  Hash Full Join
+               Hash Cond: (prt1_p4.a = ((prt1_e_p4.a + prt1_e_p4.b) / 2))
+               Filter: ((prt1_p4.a = (50)) OR (prt2_p4.b = (75)) OR (((prt1_e_p4.a + prt1_e_p4.b) / 2) = (50)))
+               ->  Hash Full Join
+                     Hash Cond: (prt1_p4.a = prt2_p4.b)
+                     ->  Seq Scan on prt1_p4
+                           Filter: (b = 0)
+                     ->  Hash
+                           ->  Seq Scan on prt2_p4
+                                 Filter: (a = 0)
+               ->  Hash
+                     ->  Seq Scan on prt1_e_p4
+                           Filter: (c = 0)
+(68 rows)
 
 SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0) t1 FULL JOIN (SELECT 75 phv, * FROM prt2 WHERE prt2.a = 0) t2 ON (t1.a = t2.b)) FULL JOIN (SELECT 50 phv, * FROM prt1_e WHERE prt1_e.c = 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 
@@ -751,172 +1168,260 @@ SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHER
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
-               Join Filter: (t1.a = t1_3.b)
+               Join Filter: (t1.a = t1_5.b)
                ->  HashAggregate
-                     Group Key: t1_3.b
+                     Group Key: t1_5.b
                      ->  Hash Join
-                           Hash Cond: (((t2.a + t2.b) / 2) = t1_3.b)
-                           ->  Seq Scan on prt1_e_p1 t2
+                           Hash Cond: (((t2.a + t2.b) / 2) = t1_5.b)
+                           ->  Seq Scan on prt1_e_p0 t2
                            ->  Hash
-                                 ->  Seq Scan on prt2_p1 t1_3
+                                 ->  Seq Scan on prt2_p0 t1_5
                                        Filter: (a = 0)
-               ->  Index Scan using iprt1_p1_a on prt1_p1 t1
+               ->  Index Scan using iprt1_p0_a on prt1_p0 t1
                      Index Cond: (a = ((t2.a + t2.b) / 2))
                      Filter: (b = 0)
          ->  Nested Loop
-               Join Filter: (t1_1.a = t1_4.b)
+               Join Filter: (t1_1.a = t1_6.b)
                ->  HashAggregate
-                     Group Key: t1_4.b
+                     Group Key: t1_6.b
                      ->  Hash Join
-                           Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_4.b)
-                           ->  Seq Scan on prt1_e_p2 t2_1
+                           Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_6.b)
+                           ->  Seq Scan on prt1_e_p1 t2_1
                            ->  Hash
-                                 ->  Seq Scan on prt2_p2 t1_4
+                                 ->  Seq Scan on prt2_p1 t1_6
                                        Filter: (a = 0)
-               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_1
+               ->  Index Scan using iprt1_p1_a on prt1_p1 t1_1
                      Index Cond: (a = ((t2_1.a + t2_1.b) / 2))
                      Filter: (b = 0)
          ->  Nested Loop
-               Join Filter: (t1_2.a = t1_5.b)
+               Join Filter: (t1_2.a = t1_7.b)
                ->  HashAggregate
-                     Group Key: t1_5.b
+                     Group Key: t1_7.b
                      ->  Nested Loop
-                           ->  Seq Scan on prt2_p3 t1_5
+                           ->  Seq Scan on prt2_p2 t1_7
                                  Filter: (a = 0)
-                           ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_2
-                                 Index Cond: (((a + b) / 2) = t1_5.b)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
+                           ->  Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t2_2
+                                 Index Cond: (((a + b) / 2) = t1_7.b)
+               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_2
                      Index Cond: (a = ((t2_2.a + t2_2.b) / 2))
                      Filter: (b = 0)
-(41 rows)
+         ->  Nested Loop
+               Join Filter: (t1_3.a = t1_8.b)
+               ->  HashAggregate
+                     Group Key: t1_8.b
+                     ->  Nested Loop
+                           ->  Seq Scan on prt2_p3 t1_8
+                                 Filter: (a = 0)
+                           ->  Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_3
+                                 Index Cond: (((a + b) / 2) = t1_8.b)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = ((t2_3.a + t2_3.b) / 2))
+                     Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: (t1_4.a = t1_9.b)
+               ->  HashAggregate
+                     Group Key: t1_9.b
+                     ->  Hash Join
+                           Hash Cond: (((t2_4.a + t2_4.b) / 2) = t1_9.b)
+                           ->  Seq Scan on prt1_e_p4 t2_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t1_9
+                                       Filter: (a = 0)
+               ->  Index Scan using iprt1_p4_a on prt1_p4 t1_4
+                     Index Cond: (a = ((t2_4.a + t2_4.b) / 2))
+                     Filter: (b = 0)
+(66 rows)
 
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.a = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 EXPLAIN (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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-                               QUERY PLAN                                
--------------------------------------------------------------------------
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
  Sort
    Sort Key: t1.a
    ->  Append
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_3.b
+                     Group Key: t1_5.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_3.b = ((t1_6.a + t1_6.b) / 2))
-                           ->  Seq Scan on prt2_p1 t1_3
+                           Hash Cond: (t1_5.b = ((t1_10.a + t1_10.b) / 2))
+                           ->  Seq Scan on prt2_p0 t1_5
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p1 t1_6
+                                 ->  Seq Scan on prt1_e_p0 t1_10
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p1_a on prt1_p1 t1
-                     Index Cond: (a = t1_3.b)
+               ->  Index Scan using iprt1_p0_a on prt1_p0 t1
+                     Index Cond: (a = t1_5.b)
                      Filter: (b = 0)
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_4.b
+                     Group Key: t1_6.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_4.b = ((t1_7.a + t1_7.b) / 2))
-                           ->  Seq Scan on prt2_p2 t1_4
+                           Hash Cond: (t1_6.b = ((t1_11.a + t1_11.b) / 2))
+                           ->  Seq Scan on prt2_p1 t1_6
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p2 t1_7
+                                 ->  Seq Scan on prt1_e_p1 t1_11
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_1
-                     Index Cond: (a = t1_4.b)
+               ->  Index Scan using iprt1_p1_a on prt1_p1 t1_1
+                     Index Cond: (a = t1_6.b)
                      Filter: (b = 0)
          ->  Nested Loop
                ->  HashAggregate
-                     Group Key: t1_5.b
+                     Group Key: t1_7.b
                      ->  Hash Semi Join
-                           Hash Cond: (t1_5.b = ((t1_8.a + t1_8.b) / 2))
-                           ->  Seq Scan on prt2_p3 t1_5
+                           Hash Cond: (t1_7.b = ((t1_12.a + t1_12.b) / 2))
+                           ->  Seq Scan on prt2_p2 t1_7
                            ->  Hash
-                                 ->  Seq Scan on prt1_e_p3 t1_8
+                                 ->  Seq Scan on prt1_e_p2 t1_12
                                        Filter: (c = 0)
-               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_2
-                     Index Cond: (a = t1_5.b)
+               ->  Index Scan using iprt1_p2_a on prt1_p2 t1_2
+                     Index Cond: (a = t1_7.b)
                      Filter: (b = 0)
-(39 rows)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t1_8.b
+                     ->  Hash Semi Join
+                           Hash Cond: (t1_8.b = ((t1_13.a + t1_13.b) / 2))
+                           ->  Seq Scan on prt2_p3 t1_8
+                           ->  Hash
+                                 ->  Seq Scan on prt1_e_p3 t1_13
+                                       Filter: (c = 0)
+               ->  Index Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t1_8.b)
+                     Filter: (b = 0)
+         ->  Nested Loop
+               ->  HashAggregate
+                     Group Key: t1_9.b
+                     ->  Hash Semi Join
+                           Hash Cond: (t1_9.b = ((t1_14.a + t1_14.b) / 2))
+                           ->  Seq Scan on prt2_p4 t1_9
+                           ->  Hash
+                                 ->  Seq Scan on prt1_e_p4 t1_14
+                                       Filter: (c = 0)
+               ->  Index Scan using iprt1_p4_a on prt1_p4 t1_4
+                     Index Cond: (a = t1_9.b)
+                     Filter: (b = 0)
+(63 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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 -- test merge joins
 SET enable_hashjoin TO off;
 SET enable_nestloop TO off;
 EXPLAIN (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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-                           QUERY PLAN                           
-----------------------------------------------------------------
+                            QUERY PLAN                            
+------------------------------------------------------------------
  Merge Append
    Sort Key: t1.a
    ->  Merge Semi Join
-         Merge Cond: (t1.a = t1_3.b)
+         Merge Cond: (t1.a = t1_5.b)
          ->  Sort
                Sort Key: t1.a
-               ->  Seq Scan on prt1_p1 t1
+               ->  Seq Scan on prt1_p0 t1
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_3.b = (((t1_6.a + t1_6.b) / 2)))
+               Merge Cond: (t1_5.b = (((t1_10.a + t1_10.b) / 2)))
                ->  Sort
-                     Sort Key: t1_3.b
-                     ->  Seq Scan on prt2_p1 t1_3
+                     Sort Key: t1_5.b
+                     ->  Seq Scan on prt2_p0 t1_5
                ->  Sort
-                     Sort Key: (((t1_6.a + t1_6.b) / 2))
-                     ->  Seq Scan on prt1_e_p1 t1_6
+                     Sort Key: (((t1_10.a + t1_10.b) / 2))
+                     ->  Seq Scan on prt1_e_p0 t1_10
                            Filter: (c = 0)
    ->  Merge Semi Join
-         Merge Cond: (t1_1.a = t1_4.b)
+         Merge Cond: (t1_1.a = t1_6.b)
          ->  Sort
                Sort Key: t1_1.a
-               ->  Seq Scan on prt1_p2 t1_1
+               ->  Seq Scan on prt1_p1 t1_1
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_4.b = (((t1_7.a + t1_7.b) / 2)))
+               Merge Cond: (t1_6.b = (((t1_11.a + t1_11.b) / 2)))
                ->  Sort
-                     Sort Key: t1_4.b
-                     ->  Seq Scan on prt2_p2 t1_4
+                     Sort Key: t1_6.b
+                     ->  Seq Scan on prt2_p1 t1_6
                ->  Sort
-                     Sort Key: (((t1_7.a + t1_7.b) / 2))
-                     ->  Seq Scan on prt1_e_p2 t1_7
+                     Sort Key: (((t1_11.a + t1_11.b) / 2))
+                     ->  Seq Scan on prt1_e_p1 t1_11
                            Filter: (c = 0)
    ->  Merge Semi Join
-         Merge Cond: (t1_2.a = t1_5.b)
+         Merge Cond: (t1_2.a = t1_7.b)
          ->  Sort
                Sort Key: t1_2.a
-               ->  Seq Scan on prt1_p3 t1_2
+               ->  Seq Scan on prt1_p2 t1_2
                      Filter: (b = 0)
          ->  Merge Semi Join
-               Merge Cond: (t1_5.b = (((t1_8.a + t1_8.b) / 2)))
+               Merge Cond: (t1_7.b = (((t1_12.a + t1_12.b) / 2)))
                ->  Sort
-                     Sort Key: t1_5.b
-                     ->  Seq Scan on prt2_p3 t1_5
+                     Sort Key: t1_7.b
+                     ->  Seq Scan on prt2_p2 t1_7
                ->  Sort
-                     Sort Key: (((t1_8.a + t1_8.b) / 2))
-                     ->  Seq Scan on prt1_e_p3 t1_8
+                     Sort Key: (((t1_12.a + t1_12.b) / 2))
+                     ->  Seq Scan on prt1_e_p2 t1_12
                            Filter: (c = 0)
-(47 rows)
+   ->  Merge Semi Join
+         Merge Cond: (t1_3.a = t1_8.b)
+         ->  Sort
+               Sort Key: t1_3.a
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Merge Semi Join
+               Merge Cond: (t1_8.b = (((t1_13.a + t1_13.b) / 2)))
+               ->  Sort
+                     Sort Key: t1_8.b
+                     ->  Seq Scan on prt2_p3 t1_8
+               ->  Sort
+                     Sort Key: (((t1_13.a + t1_13.b) / 2))
+                     ->  Seq Scan on prt1_e_p3 t1_13
+                           Filter: (c = 0)
+   ->  Merge Semi Join
+         Merge Cond: (t1_4.a = t1_9.b)
+         ->  Sort
+               Sort Key: t1_4.a
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Merge Semi Join
+               Merge Cond: (t1_9.b = (((t1_14.a + t1_14.b) / 2)))
+               ->  Sort
+                     Sort Key: t1_9.b
+                     ->  Seq Scan on prt2_p4 t1_9
+               ->  Sort
+                     Sort Key: (((t1_14.a + t1_14.b) / 2))
+                     ->  Seq Scan on prt1_e_p4 t1_14
+                           Filter: (c = 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.c = 0)) AND t1.b = 0 ORDER BY t1.a;
-  a  | b |  c   
------+---+------
-   0 | 0 | 0000
- 150 | 0 | 0150
- 300 | 0 | 0300
- 450 | 0 | 0450
-(4 rows)
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
 
 EXPLAIN (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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
@@ -933,14 +1438,14 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3.a + t3.b) / 2)) = t1.a)
                            ->  Sort
                                  Sort Key: (((t3.a + t3.b) / 2))
-                                 ->  Seq Scan on prt1_e_p1 t3
+                                 ->  Seq Scan on prt1_e_p0 t3
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1.a
-                                 ->  Seq Scan on prt1_p1 t1
+                                 ->  Seq Scan on prt1_p0 t1
                ->  Sort
                      Sort Key: t2.b
-                     ->  Seq Scan on prt2_p1 t2
+                     ->  Seq Scan on prt2_p0 t2
          ->  Merge Left Join
                Merge Cond: (t1_1.a = t2_1.b)
                ->  Sort
@@ -949,14 +1454,14 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3_1.a + t3_1.b) / 2)) = t1_1.a)
                            ->  Sort
                                  Sort Key: (((t3_1.a + t3_1.b) / 2))
-                                 ->  Seq Scan on prt1_e_p2 t3_1
+                                 ->  Seq Scan on prt1_e_p1 t3_1
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1_1.a
-                                 ->  Seq Scan on prt1_p2 t1_1
+                                 ->  Seq Scan on prt1_p1 t1_1
                ->  Sort
                      Sort Key: t2_1.b
-                     ->  Seq Scan on prt2_p2 t2_1
+                     ->  Seq Scan on prt2_p1 t2_1
          ->  Merge Left Join
                Merge Cond: (t1_2.a = t2_2.b)
                ->  Sort
@@ -965,32 +1470,74 @@ SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM (prt1 t1 LEFT JOIN prt2 t2
                            Merge Cond: ((((t3_2.a + t3_2.b) / 2)) = t1_2.a)
                            ->  Sort
                                  Sort Key: (((t3_2.a + t3_2.b) / 2))
-                                 ->  Seq Scan on prt1_e_p3 t3_2
+                                 ->  Seq Scan on prt1_e_p2 t3_2
                                        Filter: (c = 0)
                            ->  Sort
                                  Sort Key: t1_2.a
-                                 ->  Seq Scan on prt1_p3 t1_2
+                                 ->  Seq Scan on prt1_p2 t1_2
                ->  Sort
                      Sort Key: t2_2.b
-                     ->  Seq Scan on prt2_p3 t2_2
-(51 rows)
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Merge Left Join
+               Merge Cond: (t1_3.a = t2_3.b)
+               ->  Sort
+                     Sort Key: t1_3.a
+                     ->  Merge Left Join
+                           Merge Cond: ((((t3_3.a + t3_3.b) / 2)) = t1_3.a)
+                           ->  Sort
+                                 Sort Key: (((t3_3.a + t3_3.b) / 2))
+                                 ->  Seq Scan on prt1_e_p3 t3_3
+                                       Filter: (c = 0)
+                           ->  Sort
+                                 Sort Key: t1_3.a
+                                 ->  Seq Scan on prt1_p3 t1_3
+               ->  Sort
+                     Sort Key: t2_3.b
+                     ->  Seq Scan on prt2_p3 t2_3
+         ->  Merge Left Join
+               Merge Cond: (t1_4.a = t2_4.b)
+               ->  Sort
+                     Sort Key: t1_4.a
+                     ->  Merge Left Join
+                           Merge Cond: ((((t3_4.a + t3_4.b) / 2)) = t1_4.a)
+                           ->  Sort
+                                 Sort Key: (((t3_4.a + t3_4.b) / 2))
+                                 ->  Seq Scan on prt1_e_p4 t3_4
+                                       Filter: (c = 0)
+                           ->  Sort
+                                 Sort Key: t1_4.a
+                                 ->  Seq Scan on prt1_p4 t1_4
+               ->  Sort
+                     Sort Key: t2_4.b
+                     ->  Seq Scan on prt2_p4 t2_4
+(83 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.c = 0 ORDER BY t1.a, t2.b, t3.a + t3.b;
-  a  |  c   |  b  |  c   | ?column? | c 
------+------+-----+------+----------+---
-   0 | 0000 |   0 | 0000 |        0 | 0
-  50 | 0050 |     |      |      100 | 0
- 100 | 0100 |     |      |      200 | 0
- 150 | 0150 | 150 | 0150 |      300 | 0
- 200 | 0200 |     |      |      400 | 0
- 250 | 0250 |     |      |      500 | 0
- 300 | 0300 | 300 | 0300 |      600 | 0
- 350 | 0350 |     |      |      700 | 0
- 400 | 0400 |     |      |      800 | 0
- 450 | 0450 | 450 | 0450 |      900 | 0
- 500 | 0500 |     |      |     1000 | 0
- 550 | 0550 |     |      |     1100 | 0
-(12 rows)
+  a   |   c   |  b   |   c   | ?column? | c 
+------+-------+------+-------+----------+---
+ -250 | -0250 |      |       |     -500 | 0
+ -200 | -0200 |      |       |     -400 | 0
+ -150 | -0150 | -150 | -0150 |     -300 | 0
+ -100 | -0100 |      |       |     -200 | 0
+  -50 | -0050 |      |       |     -100 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+    0 | 0000  |    0 | 0000  |        0 | 0
+   50 | 0050  |      |       |      100 | 0
+  100 | 0100  |      |       |      200 | 0
+  150 | 0150  |  150 | 0150  |      300 | 0
+  200 | 0200  |      |       |      400 | 0
+  250 | 0250  |      |       |      500 | 0
+  300 | 0300  |  300 | 0300  |      600 | 0
+  350 | 0350  |      |       |      700 | 0
+  400 | 0400  |      |       |      800 | 0
+  450 | 0450  |  450 | 0450  |      900 | 0
+  500 | 0500  |      |       |     1000 | 0
+  550 | 0550  |      |       |     1100 | 0
+  600 | 0600  |  600 | 0600  |     1200 | 0
+  650 | 0650  |      |       |     1300 | 0
+  700 | 0700  |      |       |     1400 | 0
+  750 | 0750  |  750 | 0750  |     1500 | 0
+(22 rows)
 
 -- MergeAppend on nullable column
 EXPLAIN (COSTS OFF)
@@ -998,8 +1545,18 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
                         QUERY PLAN                         
 -----------------------------------------------------------
  Sort
-   Sort Key: prt1_p1.a, b
+   Sort Key: prt1_p0.a, b
    ->  Append
+         ->  Merge Left Join
+               Merge Cond: (prt1_p0.a = b)
+               ->  Sort
+                     Sort Key: prt1_p0.a
+                     ->  Seq Scan on prt1_p0
+                           Filter: ((a < 450) AND (b = 0))
+               ->  Sort
+                     Sort Key: b
+                     ->  Result
+                           One-Time Filter: false
          ->  Merge Left Join
                Merge Cond: (prt1_p1.a = b)
                ->  Sort
@@ -1020,21 +1577,26 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT *
                      Sort Key: prt2_p2.b
                      ->  Seq Scan on prt2_p2
                            Filter: (b > 250)
-(23 rows)
+(33 rows)
 
 SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
-  a  |  b  
------+-----
-   0 |    
-  50 |    
- 100 |    
- 150 |    
- 200 |    
- 250 |    
- 300 | 300
- 350 |    
- 400 |    
-(9 rows)
+  a   |  b  
+------+-----
+ -250 |    
+ -200 |    
+ -150 |    
+ -100 |    
+  -50 |    
+    0 |    
+   50 |    
+  100 |    
+  150 |    
+  200 |    
+  250 |    
+  300 | 300
+  350 |    
+  400 |    
+(14 rows)
 
 -- merge join when expression with whole-row reference needs to be sorted;
 -- partitionwise join does not apply
@@ -1048,175 +1610,2412 @@ SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.
          Sort Key: t1.a, ((((t1.*)::prt1))::text)
          ->  Result
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
-                     ->  Seq Scan on prt1_p2 t1_1
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p0 t1
+                     ->  Seq Scan on prt1_p1 t1_1
+                     ->  Seq Scan on prt1_p2 t1_2
+                     ->  Seq Scan on prt1_p3 t1_3
+                     ->  Seq Scan on prt1_p4 t1_4
    ->  Sort
          Sort Key: t2.b, ((((t2.*)::prt2))::text)
          ->  Result
                ->  Append
-                     ->  Seq Scan on prt2_p1 t2
-                     ->  Seq Scan on prt2_p2 t2_1
-                     ->  Seq Scan on prt2_p3 t2_2
-(16 rows)
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+(20 rows)
 
 SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
- a  | b  
-----+----
-  0 |  0
-  6 |  6
- 12 | 12
- 18 | 18
- 24 | 24
-(5 rows)
+  a  |  b  
+-----+-----
+ -24 | -24
+ -18 | -18
+ -12 | -12
+  -6 |  -6
+   0 |   0
+   6 |   6
+  12 |  12
+  18 |  18
+  24 |  24
+(9 rows)
 
 RESET enable_hashjoin;
 RESET enable_nestloop;
---
--- partitioned by multiple columns
---
-CREATE TABLE prt1_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 2) i;
-ANALYZE prt1_m;
-CREATE TABLE prt2_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 3) i;
-ANALYZE prt2_m;
+-- test default partition behavior for range, partition-wise join is not
+-- possible since more than one partition on one side matches default partition
+-- on the other side. Default partition from prt1 matches default partition and
+-- prt2_p4 from prt2 and default partition from prt2 matches default partition
+-- and prt1_p0 from prt1
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
+ANALYZE prt2;
 EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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                                                             
-------------------------------------------------------------------------------------------------------------------------------------
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p4 t2_3
+               ->  Seq Scan on prt2_p3 t2_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_4
+                           Filter: (b = 0)
+(22 rows)
+
+-- partition-wise join should be possible when we drop the first and last
+-- partitions from both sides
+ALTER TABLE prt1 DETACH PARTITION prt1_p0;
+ALTER TABLE prt1 DETACH PARTITION prt1_p4;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p0;
+ALTER TABLE prt2 DETACH PARTITION prt2_p4;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p1 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p2 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p3 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p3 t1_2
+                           Filter: (b = 0)
+(21 rows)
+
+-- restore the partitioned tables for rest of the tests
+ALTER TABLE prt1 ATTACH PARTITION prt1_p0 FOR VALUES FROM (MINVALUE) TO (0);
+ALTER TABLE prt1 ATTACH PARTITION prt1_p4 FOR VALUES FROM (600) TO (800);
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt1;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p0 FOR VALUES FROM (-250) TO (0);
+ALTER TABLE prt2 ATTACH PARTITION prt2_p4 FOR VALUES FROM (600) TO (MAXVALUE);
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt2;
+-- Add an extra partition to prt2 , Partition-wise join is possible with
+-- extra partitions on inner side are allowed
+DROP TABLE prt2_p4;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (800);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (800) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999) i WHERE i % 3 = 0;
+ANALYZE prt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p0 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Hash Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+         ->  Nested Loop
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+  a   |   c   | a |   c   
+------+-------+---+-------
+ -150 | -0150 | 0 | -0150
+    0 | 0000  | 0 | 0000
+  150 | 0150  | 0 | 0150
+  300 | 0300  | 0 | 0300
+  450 | 0450  | 0 | 0450
+  600 | 0600  | 0 | 0600
+  750 | 0750  | 0 | 0750
+(7 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: (t2.b = t1.a)
+               ->  Seq Scan on prt2_p0 t2
+               ->  Hash
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+         ->  Hash Right Join
+               Hash Cond: (t2_1.b = t1_1.a)
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Hash Right Join
+               Hash Cond: (t2_2.b = t1_2.a)
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+         ->  Nested Loop Left Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (t1_3.a = b)
+         ->  Hash Right Join
+               Hash Cond: (t2_4.b = t1_4.a)
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Hash
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(32 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+  a   |   c   | a |   c   
+------+-------+---+-------
+ -250 | -0250 |   | 
+ -200 | -0200 |   | 
+ -150 | -0150 | 0 | -0150
+ -100 | -0100 |   | 
+  -50 | -0050 |   | 
+    0 | 0000  | 0 | 0000
+   50 | 0050  |   | 
+  100 | 0100  |   | 
+  150 | 0150  | 0 | 0150
+  200 | 0200  |   | 
+  250 | 0250  |   | 
+  300 | 0300  | 0 | 0300
+  350 | 0350  |   | 
+  400 | 0400  |   | 
+  450 | 0450  | 0 | 0450
+  500 | 0500  |   | 
+  550 | 0550  |   | 
+  600 | 0600  | 0 | 0600
+  650 | 0650  |   | 
+  700 | 0700  |   | 
+  750 | 0750  | 0 | 0750
+(21 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Semi Join
+               Hash Cond: (t1.a = t2.b)
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0 t2
+         ->  Hash Semi Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+         ->  Hash Semi Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Only Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Semi Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(32 rows)
+
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a   | b |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Append
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p0_a on prt1_p0 t2
+                     Index Cond: (a = t1.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p1_a on prt1_p1 t2_1
+                     Index Cond: (a = t1_1.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
+                     Index Cond: (a = t1_2.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p3_a on prt1_p3 t2_3
+                     Index Cond: (a = t1_3.b)
+         ->  Nested Loop Semi Join
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Index Only Scan using iprt1_p4_a on prt1_p4 t2_4
+                     Index Cond: (a = t1_4.b)
+(28 rows)
+
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+ a |  b   |   c   
+---+------+-------
+ 0 | -150 | -0150
+ 0 |    0 | 0000
+ 0 |  150 | 0150
+ 0 |  300 | 0300
+ 0 |  450 | 0450
+ 0 |  600 | 0600
+ 0 |  750 | 0750
+(7 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                             QUERY PLAN                             
+--------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: (t1.a = t2.b)
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p0 t2
+         ->  Hash Anti Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p1 t2_1
+         ->  Hash Anti Join
+               Hash Cond: (t1_2.a = t2_2.b)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Index Only Scan using iprt2_p3_b on prt2_p3 t2_3
+                     Index Cond: (b = t1_3.a)
+         ->  Hash Anti Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_p4 t2_4
+(32 rows)
+
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a   | b |   c   
+------+---+-------
+ -250 | 0 | -0250
+ -200 | 0 | -0200
+ -100 | 0 | -0100
+  -50 | 0 | -0050
+   50 | 0 | 0050
+  100 | 0 | 0100
+  200 | 0 | 0200
+  250 | 0 | 0250
+  350 | 0 | 0350
+  400 | 0 | 0400
+  500 | 0 | 0500
+  550 | 0 | 0550
+  650 | 0 | 0650
+  700 | 0 | 0700
+(14 rows)
+
+-- 3-way join when not every pair of joining relation can use partition-wise
+-- join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t3.c
+   ->  Append
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p0 t2
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p0_a on prt1_p0 t3
+                           Index Cond: (a = t2.b)
+               ->  Index Only Scan using iprt1_p0_a on prt1_p0 t1
+                     Index Cond: (a = t2.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_1.a = t2_1.b)
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Hash
+                     ->  Hash Join
+                           Hash Cond: (t3_1.a = t2_1.b)
+                           ->  Seq Scan on prt1_p1 t3_1
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p1 t2_1
+                                       Filter: (a = 0)
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p2 t2_2
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p2_a on prt1_p2 t3_2
+                           Index Cond: (a = t2_2.b)
+               ->  Index Only Scan using iprt1_p2_a on prt1_p2 t1_2
+                     Index Cond: (a = t2_2.b)
+         ->  Nested Loop Left Join
+               ->  Nested Loop
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+                     ->  Index Scan using iprt1_p3_a on prt1_p3 t3_3
+                           Index Cond: (a = t2_3.b)
+               ->  Index Only Scan using iprt1_p3_a on prt1_p3 t1_3
+                     Index Cond: (a = t2_3.b)
+         ->  Hash Right Join
+               Hash Cond: (t1_4.a = t2_4.b)
+               ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Hash Join
+                           Hash Cond: (t3_4.a = t2_4.b)
+                           ->  Seq Scan on prt1_p4 t3_4
+                           ->  Hash
+                                 ->  Seq Scan on prt2_p4 t2_4
+                                       Filter: (a = 0)
+(47 rows)
+
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+  a   | a |   c   
+------+---+-------
+ -150 | 0 | -0150
+    0 | 0 | 0000
+  150 | 0 | 0150
+  300 | 0 | 0300
+  450 | 0 | 0450
+  600 | 0 | 0600
+  750 | 0 | 0750
+(7 rows)
+
+-- partition-wise join can not handle missing partition on the inner side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.b;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.b
+   ->  Hash Right Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p1 t2_1
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p2 t2_2
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p3 t2_3
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p4 t2_4
+                           Filter: (a = 0)
+                     ->  Seq Scan on prt2_p5 t2_5
+                           Filter: (a = 0)
+(24 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE coalesce(t1.b, 0) + coalesce(t2.a, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: (t1.a = t2.b)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.a, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(19 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE prt2_p4;
+DROP TABLE prt2_p5;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (700);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (700) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999, 3) i;
+ANALYZE prt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Right Join
+         Hash Cond: (t2.b = t1.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p1 t1_1
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p2 t1_2
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.a;
+                 QUERY PLAN                 
+--------------------------------------------
+ Hash Right Join
+   Hash Cond: (t1.a = t2.b)
+   ->  Append
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t2_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t2_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t2_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t2_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t2_5
+                     Filter: (a = 0)
+(22 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b + t2.a = 0 ORDER BY t1.a, t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Join
+         Hash Cond: (t1.a = t2.b)
+         Join Filter: ((t1.b + t2.a) = 0)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+               ->  Seq Scan on prt1_p1 t1_1
+               ->  Seq Scan on prt1_p2 t1_2
+               ->  Seq Scan on prt1_p3 t1_3
+               ->  Seq Scan on prt1_p4 t1_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(19 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Semi Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Semi Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on prt1_p4 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.b, t1.c
+   ->  Hash Anti Join
+         Hash Cond: (t1.b = t2.a)
+         ->  Append
+               ->  Seq Scan on prt2_p0 t1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p1 t1_1
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p2 t1_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t1_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t1_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t1_5
+                     Filter: (a = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t2
+                     ->  Seq Scan on prt1_p1 t2_1
+                     ->  Seq Scan on prt1_p2 t2_2
+                     ->  Seq Scan on prt1_p3 t2_3
+                     ->  Seq Scan on prt1_p4 t2_4
+(24 rows)
+
+--
+-- partitioned by multiple columns
+--
+CREATE TABLE prt1_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_m;
+CREATE TABLE prt2_m (a int, b int, c int) 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, i % 25 FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_m;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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
+   Sort Key: prt1_m_p1.a, prt2_m_p1.b
+   ->  Append
+         ->  Hash Full Join
+               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 prt1_m_p1
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p1
+                           Filter: (c = 0)
+         ->  Hash Full Join
+               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 prt1_m_p2
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p2
+                           Filter: (c = 0)
+         ->  Hash Full Join
+               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 prt1_m_p3
+                     Filter: (c = 0)
+               ->  Hash
+                     ->  Seq Scan on prt2_m_p3
+                           Filter: (c = 0)
+(24 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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 | 0 |   0 | 0
+  50 | 0 |     |  
+ 100 | 0 |     |  
+ 150 | 0 | 150 | 0
+ 200 | 0 |     |  
+ 250 | 0 |     |  
+ 300 | 0 | 300 | 0
+ 350 | 0 |     |  
+ 400 | 0 |     |  
+ 450 | 0 | 450 | 0
+ 500 | 0 |     |  
+ 550 | 0 |     |  
+     |   |  75 | 0
+     |   | 225 | 0
+     |   | 375 | 0
+     |   | 525 | 0
+(16 rows)
+
+--
+-- tests for list partitioned tables.
+--
+\set part_mod 17
+\set cond_mod 47
+\set num_rows 500
+CREATE TABLE plt1 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0001','0002','0003');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0008','0009');
+CREATE TABLE plt1_p4 PARTITION OF plt1 FOR VALUES IN ('0000','0010');
+INSERT INTO plt1 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (7, 11, 12, 13, 14, 15, 16);
+ANALYSE plt1;
+-- plt2 have missing starting 0001, additional 0007, missing ending 0010
+-- and additional 0011 and 0012 bounds
+CREATE TABLE plt2 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0002','0003');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0007','0008','0009');
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000','0011','0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 10, 13, 14, 15, 16);
+ANALYSE plt2;
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Left Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t2_2.c)::text = (t1_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + t2_2.b) = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on plt1_p2 t1_2
+         ->  Hash Right Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 0011
+(6 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                               QUERY PLAN                                
+-------------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Append
+         ->  Hash Full Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Full Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Full Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Full Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 0011
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 470 | 0 | 0011
+(1 row)
+
+--
+-- 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 ('0002', '0003');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0004', '0005', '0006');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0008', '0009');
+CREATE TABLE plt1_e_p4 PARTITION OF plt1_e FOR VALUES IN ('0000');
+INSERT INTO plt1_e SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 7, 10, 11, 12, 13, 14, 15, 16);
+ANALYZE plt1_e;
+-- test partition matching with N-way join
+EXPLAIN (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.b = t2.b AND 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                                           
+------------------------------------------------------------------------------------------------
+ GroupAggregate
+   Group Key: t1.c, t2.c, t3.c
+   ->  Sort
+         Sort Key: t1.c, t3.c
+         ->  Append
+               ->  Hash Join
+                     Hash Cond: ((t1.c)::text = ltrim(t3.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t2.b = t1.b) AND ((t2.c)::text = (t1.c)::text))
+                           ->  Seq Scan on plt2_p4 t2
+                           ->  Hash
+                                 ->  Seq Scan on plt1_p4 t1
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p4 t3
+               ->  Hash Join
+                     Hash Cond: ((t1_1.c)::text = ltrim(t3_1.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t1_1.b = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
+                           ->  Seq Scan on plt1_p1 t1_1
+                           ->  Hash
+                                 ->  Seq Scan on plt2_p1 t2_1
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p1 t3_1
+               ->  Hash Join
+                     Hash Cond: ((t1_2.c)::text = ltrim(t3_2.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t1_2.b = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
+                           ->  Seq Scan on plt1_p2 t1_2
+                           ->  Hash
+                                 ->  Seq Scan on plt2_p2 t2_2
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p2 t3_2
+               ->  Hash Join
+                     Hash Cond: ((t1_3.c)::text = ltrim(t3_3.c, 'A'::text))
+                     ->  Hash Join
+                           Hash Cond: ((t2_3.b = t1_3.b) AND ((t2_3.c)::text = (t1_3.c)::text))
+                           ->  Seq Scan on plt2_p3 t2_3
+                           ->  Hash
+                                 ->  Seq Scan on plt1_p3 t1_3
+                     ->  Hash
+                           ->  Seq Scan on plt1_e_p3 t3_3
+(41 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.b = t2.b AND 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   
+----------------------+---------------------+----------------------+------+------+------
+ 246.5000000000000000 | 22.4666666666666667 | 268.9666666666666667 | 0000 | 0000 | 0000
+ 248.5000000000000000 | 21.3333333333333333 | 269.8333333333333333 | 0002 | 0002 | 0002
+ 249.5000000000000000 | 22.3333333333333333 | 271.8333333333333333 | 0003 | 0003 | 0003
+ 250.5000000000000000 | 23.3333333333333333 | 273.8333333333333333 | 0004 | 0004 | 0004
+ 251.5000000000000000 | 22.7666666666666667 | 274.2666666666666667 | 0005 | 0005 | 0005
+ 252.5000000000000000 | 22.2000000000000000 | 274.7000000000000000 | 0006 | 0006 | 0006
+ 246.0000000000000000 | 23.9655172413793103 | 269.9655172413793103 | 0008 | 0008 | 0008
+ 247.0000000000000000 | 23.3448275862068966 | 270.3448275862068966 | 0009 | 0009 | 0009
+(8 rows)
+
+-- Add an extra partition to plt2 , Partition-wise join is possible with
+-- partitions on inner side are allowed
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (13, 14);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p4 t1
+               ->  Hash
+                     ->  Seq Scan on plt2_p4 t2
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Hash Right Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+                     ->  Seq Scan on plt2_p5 t2_4
+(17 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      |  47 | 0013
+     |      | 470 | 0011
+     |      | 235 | 0014
+(8 rows)
+
+-- full join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+                     ->  Seq Scan on plt2_p5 t2_4
+(17 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      |  47 | 0013
+     |      | 235 | 0014
+     |      | 470 | 0011
+(10 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(21 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+  47 | 0 | 0013
+ 235 | 0 | 0014
+ 470 | 0 | 0011
+(3 rows)
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt2_p5;
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0001','0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (1, 13, 14);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Join Filter: ((t1.b + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Left Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Hash Right Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+               ->  Seq Scan on plt1_p1 t1_1
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Seq Scan on plt1_p3 t1_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(17 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt2_p4 t2
+                                 ->  Seq Scan on plt2_p5 t2_1
+                                 ->  Seq Scan on plt2_p1 t2_2
+                                 ->  Seq Scan on plt2_p2 t2_3
+                                 ->  Seq Scan on plt2_p3 t2_4
+(23 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt1_p4 t2
+                                 ->  Seq Scan on plt1_p1 t2_1
+                                 ->  Seq Scan on plt1_p2 t2_2
+                                 ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                     QUERY PLAN                     
+----------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Nested Loop Anti Join
+         Join Filter: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Materialize
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p5 t2_1
+                     ->  Seq Scan on plt2_p1 t2_2
+                     ->  Seq Scan on plt2_p2 t2_3
+                     ->  Seq Scan on plt2_p3 t2_4
+(20 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p5 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_4
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(21 rows)
+
+-- partition have a NULL on one side, Partition-wise join is possible with
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- in this case NULL will be treated as addition partition bounds.
+DROP TABLE plt2_p5;
+DROP TABLE plt2_p4;
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000',NULL,'0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, case when i % :part_mod = 11 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (0,11,12);
+ANALYZE plt2;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Join Filter: ((t1.b + t2.b) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Join Filter: ((t1_1.b + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Join Filter: ((t1_2.b + t2_2.b) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Join Filter: ((t1_3.b + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(5 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Append
+         ->  Hash Right Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Right Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((t1_1.b + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((t1_2.b + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Left Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((t1_3.b + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+(7 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Sort
+   Sort Key: t2.a
+   ->  Append
+         ->  Hash Left Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Left Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + t2_1.b) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Left Join
+               Hash Cond: ((t2_2.c)::text = (t1_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + t2_2.b) = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on plt1_p2 t1_2
+         ->  Hash Right Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + t2_3.b) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 
+(6 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                               QUERY PLAN                                
+-------------------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Append
+         ->  Hash Full Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+               ->  Seq Scan on plt2_p4 t2
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t1
+         ->  Hash Full Join
+               Hash Cond: ((t2_1.c)::text = (t1_1.c)::text)
+               Filter: ((COALESCE(t1_1.b, 0) + COALESCE(t2_1.b, 0)) = 0)
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_p1 t1_1
+         ->  Hash Full Join
+               Hash Cond: ((t1_2.c)::text = (t2_2.c)::text)
+               Filter: ((COALESCE(t1_2.b, 0) + COALESCE(t2_2.b, 0)) = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+               ->  Hash
+                     ->  Seq Scan on plt2_p2 t2_2
+         ->  Hash Full Join
+               Hash Cond: ((t1_3.c)::text = (t2_3.c)::text)
+               Filter: ((COALESCE(t1_3.b, 0) + COALESCE(t2_3.b, 0)) = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+               ->  Hash
+                     ->  Seq Scan on plt2_p3 t2_3
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+  a  |  c   |  a  |  c   
+-----+------+-----+------
+   0 | 0000 |   0 | 0000
+  94 | 0009 |  94 | 0009
+ 141 | 0005 | 141 | 0005
+ 188 | 0001 |     | 
+ 282 | 0010 |     | 
+ 329 | 0006 | 329 | 0006
+ 376 | 0002 | 376 | 0002
+     |      | 470 | 
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt2_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt1_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2_1.c)::text
+                     ->  Seq Scan on plt2_p1 t2_1
+               ->  Materialize
+                     ->  Seq Scan on plt1_p1 t1_1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(29 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Seq Scan on plt1_p4 t2
+               ->  Materialize
+                     ->  Seq Scan on plt2_p4 t1
+                           Filter: (b = 0)
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Semi Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(26 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+   0 | 0 | 0000
+  94 | 0 | 0009
+ 141 | 0 | 0005
+ 329 | 0 | 0006
+ 376 | 0 | 0002
+(5 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p4 t2
+         ->  Hash Anti Join
+               Hash Cond: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt2_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b |  c   
+-----+---+------
+ 188 | 0 | 0001
+ 282 | 0 | 0010
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Append
+         ->  Hash Anti Join
+               Hash Cond: ((t1.c)::text = (t2.c)::text)
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Hash
+                     ->  Seq Scan on plt1_p4 t2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_1.c)::text = (t2_1.c)::text)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t2_1
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_2.c)::text = (t2_2.c)::text)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t2_2
+         ->  Nested Loop Anti Join
+               Join Filter: ((t1_3.c)::text = (t2_3.c)::text)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t2_3
+(24 rows)
+
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+  a  | b | c 
+-----+---+---
+ 470 | 0 | 
+(1 row)
+
+-- partition have a NULL on both side with different partition bounds w.r.t other side
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt1_p3;
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN (NULL,'0008','0009');
+INSERT INTO plt1 SELECT i, i % :cond_mod, case when i % :part_mod = 7 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (7,8,9);
+ANALYZE plt1;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Join Filter: ((t1.b + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a
+   ->  Hash Right Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((t1.b + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+                    QUERY PLAN                    
+--------------------------------------------------
  Sort
-   Sort Key: prt1_m_p1.a, prt2_m_p1.b
-   ->  Append
-         ->  Hash Full Join
-               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 prt1_m_p1
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p1
-                           Filter: (c = 0)
-         ->  Hash Full Join
-               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 prt1_m_p2
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p2
-                           Filter: (c = 0)
-         ->  Hash Full Join
-               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 prt1_m_p3
-                     Filter: (c = 0)
-               ->  Hash
-                     ->  Seq Scan on prt2_m_p3
-                           Filter: (c = 0)
-(24 rows)
+   Sort Key: t2.a
+   ->  Hash Left Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + t2.b) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
+(16 rows)
 
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1 FULL JOIN (SELECT * FROM prt2_m WHERE prt2_m.c = 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 | 0 |   0 | 0
-  50 | 0 |     |  
- 100 | 0 |     |  
- 150 | 0 | 150 | 0
- 200 | 0 |     |  
- 250 | 0 |     |  
- 300 | 0 | 300 | 0
- 350 | 0 |     |  
- 400 | 0 |     |  
- 450 | 0 | 450 | 0
- 500 | 0 |     |  
- 550 | 0 |     |  
-     |   |  75 | 0
-     |   | 225 | 0
-     |   | 375 | 0
-     |   | 525 | 0
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t2.a
+   ->  Hash Full Join
+         Hash Cond: ((t2.c)::text = (t1.c)::text)
+         Filter: ((COALESCE(t1.b, 0) + COALESCE(t2.b, 0)) = 0)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t2
+               ->  Seq Scan on plt2_p1 t2_1
+               ->  Seq Scan on plt2_p2 t2_2
+               ->  Seq Scan on plt2_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t1
+                     ->  Seq Scan on plt1_p1 t1_1
+                     ->  Seq Scan on plt1_p2 t1_2
+                     ->  Seq Scan on plt1_p3 t1_3
 (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;
-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;
---
--- 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;
--- test partition matching with N-way join
+-- semi join
 EXPLAIN (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.b = t2.b AND 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                                   
---------------------------------------------------------------------------------
- GroupAggregate
-   Group Key: t1.c, t2.c, t3.c
-   ->  Sort
-         Sort Key: t1.c, t3.c
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
          ->  Append
-               ->  Hash Join
-                     Hash Cond: (t1.c = ltrim(t3.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1.b = t2.b) AND (t1.c = t2.c))
-                           ->  Seq Scan on plt1_p1 t1
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p1 t2
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p1 t3
-               ->  Hash Join
-                     Hash Cond: (t1_1.c = ltrim(t3_1.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
-                           ->  Seq Scan on plt1_p2 t1_1
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p2 t2_1
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p2 t3_1
-               ->  Hash Join
-                     Hash Cond: (t1_2.c = ltrim(t3_2.c, 'A'::text))
-                     ->  Hash Join
-                           Hash Cond: ((t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
-                           ->  Seq Scan on plt1_p3 t1_2
-                           ->  Hash
-                                 ->  Seq Scan on plt2_p3 t2_2
-                     ->  Hash
-                           ->  Seq Scan on plt1_e_p3 t3_2
-(32 rows)
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt2_p4 t2
+                                 ->  Seq Scan on plt2_p1 t2_1
+                                 ->  Seq Scan on plt2_p2 t2_2
+                                 ->  Seq Scan on plt2_p3 t2_3
+(22 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.b = t2.b AND 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
-  75.0000000000000000 |  75.0000000000000000 |  148.0000000000000000 | 0001 | 0001 | A0001
- 123.0000000000000000 | 123.0000000000000000 |  248.0000000000000000 | 0002 | 0002 | A0002
- 174.0000000000000000 | 174.0000000000000000 |  348.0000000000000000 | 0003 | 0003 | A0003
- 225.0000000000000000 | 225.0000000000000000 |  448.0000000000000000 | 0004 | 0004 | A0004
- 273.0000000000000000 | 273.0000000000000000 |  548.0000000000000000 | 0005 | 0005 | A0005
- 324.0000000000000000 | 324.0000000000000000 |  648.0000000000000000 | 0006 | 0006 | A0006
- 375.0000000000000000 | 375.0000000000000000 |  748.0000000000000000 | 0007 | 0007 | A0007
- 423.0000000000000000 | 423.0000000000000000 |  848.0000000000000000 | 0008 | 0008 | A0008
- 474.0000000000000000 | 474.0000000000000000 |  948.0000000000000000 | 0009 | 0009 | A0009
- 525.0000000000000000 | 525.0000000000000000 | 1048.0000000000000000 | 0010 | 0010 | A0010
- 573.0000000000000000 | 573.0000000000000000 | 1148.0000000000000000 | 0011 | 0011 | A0011
-(12 rows)
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  HashAggregate
+                     Group Key: (t2.c)::text
+                     ->  Result
+                           ->  Append
+                                 ->  Seq Scan on plt1_p4 t2
+                                 ->  Seq Scan on plt1_p1 t2_1
+                                 ->  Seq Scan on plt1_p2 t2_2
+                                 ->  Seq Scan on plt1_p3 t2_3
+(22 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt1_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt1_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+(19 rows)
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Sort
+   Sort Key: t1.a, t1.c
+   ->  Hash Anti Join
+         Hash Cond: ((t1.c)::text = (t2.c)::text)
+         ->  Append
+               ->  Seq Scan on plt2_p4 t1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p1 t1_1
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p2 t1_2
+                     Filter: (b = 0)
+               ->  Seq Scan on plt2_p3 t1_3
+                     Filter: (b = 0)
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_p4 t2
+                     ->  Seq Scan on plt1_p1 t2_1
+                     ->  Seq Scan on plt1_p2 t2_2
+                     ->  Seq Scan on plt1_p3 t2_3
+(19 rows)
 
 -- joins where one of the relations is proven empty
 EXPLAIN (COSTS OFF)
@@ -1241,22 +4040,22 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
 --------------------------------------------------
  Hash Left Join
    Hash Cond: (t2.b = a)
-   ->  Append
-         ->  Hash Join
-               Hash Cond: (t3.a = t2.b)
-               ->  Seq Scan on prt1_p1 t3
-               ->  Hash
-                     ->  Seq Scan on prt2_p1 t2
-         ->  Hash Join
-               Hash Cond: (t3_1.a = t2_1.b)
-               ->  Seq Scan on prt1_p2 t3_1
-               ->  Hash
-                     ->  Seq Scan on prt2_p2 t2_1
-         ->  Hash Join
-               Hash Cond: (t3_2.a = t2_2.b)
-               ->  Seq Scan on prt1_p3 t3_2
-               ->  Hash
-                     ->  Seq Scan on prt2_p3 t2_2
+   ->  Hash Join
+         Hash Cond: (t3.a = t2.b)
+         ->  Append
+               ->  Seq Scan on prt1_p0 t3
+               ->  Seq Scan on prt1_p1 t3_1
+               ->  Seq Scan on prt1_p2 t3_2
+               ->  Seq Scan on prt1_p3 t3_3
+               ->  Seq Scan on prt1_p4 t3_4
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt2_p0 t2
+                     ->  Seq Scan on prt2_p1 t2_1
+                     ->  Seq Scan on prt2_p2 t2_2
+                     ->  Seq Scan on prt2_p3 t2_3
+                     ->  Seq Scan on prt2_p4 t2_4
+                     ->  Seq Scan on prt2_p5 t2_5
    ->  Hash
          ->  Result
                One-Time Filter: false
@@ -1271,16 +4070,22 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
    ->  Hash Left Join
          Hash Cond: (t2.b = a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
+               ->  Seq Scan on prt2_p0 t2
                      Filter: (a = 0)
-               ->  Seq Scan on prt2_p2 t2_1
+               ->  Seq Scan on prt2_p1 t2_1
                      Filter: (a = 0)
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p2 t2_2
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p3 t2_3
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p4 t2_4
+                     Filter: (a = 0)
+               ->  Seq Scan on prt2_p5 t2_5
                      Filter: (a = 0)
          ->  Hash
                ->  Result
                      One-Time Filter: false
-(14 rows)
+(20 rows)
 
 --
 -- tests for hash partitioned tables.
@@ -1356,41 +4161,9 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, ph
  273.0000000000000000 | 273.0000000000000000 | 548.0000000000000000 | 0005 | 0005 | A0005
 (6 rows)
 
--- test default partition behavior for range
-ALTER TABLE prt1 DETACH PARTITION prt1_p3;
-ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
-ANALYZE prt1;
-ALTER TABLE prt2 DETACH PARTITION prt2_p3;
-ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
-ANALYZE prt2;
-EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-                    QUERY PLAN                    
---------------------------------------------------
- Sort
-   Sort Key: t1.a
-   ->  Append
-         ->  Hash Join
-               Hash Cond: (t2.b = t1.a)
-               ->  Seq Scan on prt2_p1 t2
-               ->  Hash
-                     ->  Seq Scan on prt1_p1 t1
-                           Filter: (b = 0)
-         ->  Hash Join
-               Hash Cond: (t2_1.b = t1_1.a)
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Hash
-                     ->  Seq Scan on prt1_p2 t1_1
-                           Filter: (b = 0)
-         ->  Hash Join
-               Hash Cond: (t2_2.b = t1_2.a)
-               ->  Seq Scan on prt2_p3 t2_2
-               ->  Hash
-                     ->  Seq Scan on prt1_p3 t1_2
-                           Filter: (b = 0)
-(21 rows)
-
--- test default partition behavior for list
+-- test default partition behavior for list, should not use partition-wise join
+-- since default partition from one side matches multiple partitions on the
+-- other
 ALTER TABLE plt1 DETACH PARTITION plt1_p3;
 ALTER TABLE plt1 ATTACH PARTITION plt1_p3 DEFAULT;
 ANALYZE plt1;
@@ -1405,26 +4178,24 @@ SELECT avg(t1.a), avg(t2.b), t1.c, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c
    Sort Key: t1.c
    ->  HashAggregate
          Group Key: t1.c, t2.c
-         ->  Append
-               ->  Hash Join
-                     Hash Cond: (t2.c = t1.c)
-                     ->  Seq Scan on plt2_p1 t2
-                     ->  Hash
-                           ->  Seq Scan on plt1_p1 t1
+         ->  Hash Join
+               Hash Cond: ((t2.c)::text = (t1.c)::text)
+               ->  Append
+                     ->  Seq Scan on plt2_p4 t2
+                     ->  Seq Scan on plt2_p1 t2_1
+                     ->  Seq Scan on plt2_p2 t2_2
+                     ->  Seq Scan on plt2_p3 t2_3
+               ->  Hash
+                     ->  Append
+                           ->  Seq Scan on plt1_p4 t1
                                  Filter: ((a % 25) = 0)
-               ->  Hash Join
-                     Hash Cond: (t2_1.c = t1_1.c)
-                     ->  Seq Scan on plt2_p2 t2_1
-                     ->  Hash
-                           ->  Seq Scan on plt1_p2 t1_1
+                           ->  Seq Scan on plt1_p1 t1_1
                                  Filter: ((a % 25) = 0)
-               ->  Hash Join
-                     Hash Cond: (t2_2.c = t1_2.c)
-                     ->  Seq Scan on plt2_p3 t2_2
-                     ->  Hash
-                           ->  Seq Scan on plt1_p3 t1_2
+                           ->  Seq Scan on plt1_p2 t1_2
                                  Filter: ((a % 25) = 0)
-(23 rows)
+                           ->  Seq Scan on plt1_p3 t1_3
+                                 Filter: ((a % 25) = 0)
+(21 rows)
 
 --
 -- multiple levels of partitioning
@@ -1826,64 +4597,70 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a;
  Hash Join
    Hash Cond: (t1.a = t2.a)
    ->  Append
-         ->  Seq Scan on prt1_p1 t1
-         ->  Seq Scan on prt1_p2 t1_1
-         ->  Seq Scan on prt1_p3 t1_2
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
    ->  Hash
          ->  Append
                ->  Seq Scan on prt4_n_p1 t2
                ->  Seq Scan on prt4_n_p2 t2_1
                ->  Seq Scan on prt4_n_p3 t2_2
-(11 rows)
+(13 rows)
 
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2, prt2 t3 WHERE t1.a = t2.a and t1.a = t3.b;
-                       QUERY PLAN                       
---------------------------------------------------------
+                        QUERY PLAN                        
+----------------------------------------------------------
  Hash Join
-   Hash Cond: (t2.a = t1.a)
+   Hash Cond: (t3.b = t1.a)
    ->  Append
-         ->  Seq Scan on prt4_n_p1 t2
-         ->  Seq Scan on prt4_n_p2 t2_1
-         ->  Seq Scan on prt4_n_p3 t2_2
+         ->  Seq Scan on prt2_p0 t3
+         ->  Seq Scan on prt2_p1 t3_1
+         ->  Seq Scan on prt2_p2 t3_2
+         ->  Seq Scan on prt2_p3 t3_3
+         ->  Seq Scan on prt2_p4 t3_4
+         ->  Seq Scan on prt2_p5 t3_5
    ->  Hash
-         ->  Append
-               ->  Hash Join
-                     Hash Cond: (t1.a = t3.b)
-                     ->  Seq Scan on prt1_p1 t1
-                     ->  Hash
-                           ->  Seq Scan on prt2_p1 t3
-               ->  Hash Join
-                     Hash Cond: (t1_1.a = t3_1.b)
-                     ->  Seq Scan on prt1_p2 t1_1
-                     ->  Hash
-                           ->  Seq Scan on prt2_p2 t3_1
-               ->  Hash Join
-                     Hash Cond: (t1_2.a = t3_2.b)
-                     ->  Seq Scan on prt1_p3 t1_2
-                     ->  Hash
-                           ->  Seq Scan on prt2_p3 t3_2
+         ->  Hash Join
+               Hash Cond: (t1.a = t2.a)
+               ->  Append
+                     ->  Seq Scan on prt1_p0 t1
+                     ->  Seq Scan on prt1_p1 t1_1
+                     ->  Seq Scan on prt1_p2 t1_2
+                     ->  Seq Scan on prt1_p3 t1_3
+                     ->  Seq Scan on prt1_p4 t1_4
+               ->  Hash
+                     ->  Append
+                           ->  Seq Scan on prt4_n_p1 t2
+                           ->  Seq Scan on prt4_n_p2 t2_1
+                           ->  Seq Scan on prt4_n_p3 t2_2
 (23 rows)
 
 -- partitionwise 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                        
----------------------------------------------------------
+                 QUERY PLAN                 
+--------------------------------------------
  Nested Loop Left Join
+   Join Filter: (t1.a < t2.b)
    ->  Append
-         ->  Seq Scan on prt1_p1 t1
-         ->  Seq Scan on prt1_p2 t1_1
-         ->  Seq Scan on prt1_p3 t1_2
-   ->  Append
-         ->  Index Scan using iprt2_p1_b on prt2_p1 t2
-               Index Cond: (t1.a < b)
-         ->  Index Scan using iprt2_p2_b on prt2_p2 t2_1
-               Index Cond: (t1.a < b)
-         ->  Index Scan using iprt2_p3_b on prt2_p3 t2_2
-               Index Cond: (t1.a < b)
-(12 rows)
+         ->  Seq Scan on prt1_p0 t1
+         ->  Seq Scan on prt1_p1 t1_1
+         ->  Seq Scan on prt1_p2 t1_2
+         ->  Seq Scan on prt1_p3 t1_3
+         ->  Seq Scan on prt1_p4 t1_4
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
+(16 rows)
 
 -- equi-join with join condition on partial keys does not qualify for
 -- partitionwise join
@@ -1969,16 +4746,17 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 JOIN prt2_n t2 ON (t1.c = t2.c) JOI
          ->  Seq Scan on prt2_n_p2 t2_1
    ->  Hash
          ->  Hash Join
-               Hash Cond: (t3.c = (t1.c)::text)
+               Hash Cond: ((t3.c)::text = (t1.c)::text)
                ->  Append
-                     ->  Seq Scan on plt1_p1 t3
-                     ->  Seq Scan on plt1_p2 t3_1
-                     ->  Seq Scan on plt1_p3 t3_2
+                     ->  Seq Scan on plt1_p4 t3
+                     ->  Seq Scan on plt1_p1 t3_1
+                     ->  Seq Scan on plt1_p2 t3_2
+                     ->  Seq Scan on plt1_p3 t3_3
                ->  Hash
                      ->  Append
                            ->  Seq Scan on prt1_n_p1 t1
                            ->  Seq Scan on prt1_n_p2 t1_1
-(16 rows)
+(17 rows)
 
 -- partitionwise join can not be applied for a join between list and range
 -- partitioned table
@@ -1989,14 +4767,16 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c);
  Hash Full Join
    Hash Cond: ((t2.c)::text = (t1.c)::text)
    ->  Append
-         ->  Seq Scan on prt1_p1 t2
-         ->  Seq Scan on prt1_p2 t2_1
-         ->  Seq Scan on prt1_p3 t2_2
+         ->  Seq Scan on prt1_p0 t2
+         ->  Seq Scan on prt1_p1 t2_1
+         ->  Seq Scan on prt1_p2 t2_2
+         ->  Seq Scan on prt1_p3 t2_3
+         ->  Seq Scan on prt1_p4 t2_4
    ->  Hash
          ->  Append
                ->  Seq Scan on prt1_n_p1 t1
                ->  Seq Scan on prt1_n_p2 t1_1
-(10 rows)
+(12 rows)
 
 -- partitionwise join can not be applied if only one of joining table has
 -- default partition
@@ -2012,16 +4792,23 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b =
    ->  Hash Join
          Hash Cond: (t2.b = t1.a)
          ->  Append
-               ->  Seq Scan on prt2_p1 t2
-               ->  Seq Scan on prt2_p2 t2_1
-               ->  Seq Scan on prt2_p3 t2_2
+               ->  Seq Scan on prt2_p0 t2
+               ->  Seq Scan on prt2_p1 t2_1
+               ->  Seq Scan on prt2_p2 t2_2
+               ->  Seq Scan on prt2_p3 t2_3
+               ->  Seq Scan on prt2_p4 t2_4
+               ->  Seq Scan on prt2_p5 t2_5
          ->  Hash
                ->  Append
-                     ->  Seq Scan on prt1_p1 t1
+                     ->  Seq Scan on prt1_p0 t1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p2 t1_1
+                     ->  Seq Scan on prt1_p1 t1_1
                            Filter: (b = 0)
-                     ->  Seq Scan on prt1_p3 t1_2
+                     ->  Seq Scan on prt1_p2 t1_2
                            Filter: (b = 0)
-(16 rows)
+                     ->  Seq Scan on prt1_p3 t1_3
+                           Filter: (b = 0)
+                     ->  Seq Scan on prt1_p4 t1_4
+                           Filter: (b = 0)
+(23 rows)
 
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index c1c9859651..0e884835fb 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -10,25 +10,39 @@ SET enable_partitionwise_join to true;
 -- partitioned by a single column
 --
 CREATE TABLE prt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_p0 PARTITION OF prt1 FOR VALUES FROM (MINVALUE) TO (0);
 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 % 25, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 2 = 0;
+CREATE TABLE prt1_p4 PARTITION OF prt1 FOR VALUES FROM (600) TO (800);
+INSERT INTO prt1 SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 2 = 0;
+CREATE INDEX iprt1_p0_a on prt1_p0(a);
 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 iprt1_p4_a on prt1_p4(a);
 ANALYZE prt1;
 
+-- prt2 have missing starting MINVALUE to -250 range and
+-- extra bounds from 800 to MAXVALUE
 CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p0 PARTITION OF prt2 FOR VALUES FROM (-250) TO (0);
 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 % 25, i, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 3 = 0;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (MAXVALUE);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(-250, 799) i WHERE i % 3 = 0;
+CREATE INDEX iprt2_p0_b on prt2_p0(b);
 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 iprt2_p4_b on prt2_p4(b);
 ANALYZE prt2;
 
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
+
 -- inner join
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
@@ -67,11 +81,19 @@ EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
 SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t2.b FROM prt2 t2 WHERE t2.a = 0) AND t1.b = 0 ORDER BY t1.a;
 
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+SELECT t1.* FROM prt2 t1 WHERE t1.b IN (SELECT t2.a FROM prt1 t2 WHERE t2.b = 0) AND t1.a = 0 ORDER BY t1.b;
+
 -- Anti-join with aggregates
 EXPLAIN (COSTS OFF)
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
 SELECT sum(t1.a), avg(t1.a), sum(t1.b), avg(t1.b) FROM prt1 t1 WHERE NOT EXISTS (SELECT 1 FROM prt2 t2 WHERE t1.a = t2.b);
 
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+SELECT t1.b, t1.c FROM prt2 t1 WHERE NOT EXISTS (SELECT 1 FROM prt1 t2 WHERE t1.b = t2.a) and t1.a = 0;
+
 -- lateral reference
 EXPLAIN (COSTS OFF)
 SELECT * FROM prt1 t1 LEFT JOIN LATERAL
@@ -93,20 +115,30 @@ SELECT t1.a, ss.t2a, ss.t2c FROM prt1 t1 LEFT JOIN LATERAL
 -- partitioned by expression
 --
 CREATE TABLE prt1_e (a int, b int, c int) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p0 PARTITION OF prt1_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt1_e_p4 PARTITION OF prt1_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(0, 599, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 2) i;
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(600, 799, 2) i;
+CREATE INDEX iprt1_e_p0_ab2 on prt1_e_p1(((a+b)/2));
 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));
+CREATE INDEX iprt1_e_p4_ab2 on prt1_e_p1(((a+b)/2));
 ANALYZE prt1_e;
 
 CREATE TABLE prt2_e (a int, b int, c int) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p0 PARTITION OF prt2_e FOR VALUES FROM (MINVALUE) TO (0);
 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);
+CREATE TABLE prt2_e_p4 PARTITION OF prt2_e FOR VALUES FROM (600) TO (MAXVALUE);
 INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(0, 599, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(-250, 0, 3) i;
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(600, 799, 3) i;
 ANALYZE prt2_e;
 
 EXPLAIN (COSTS OFF)
@@ -169,6 +201,128 @@ SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.
 RESET enable_hashjoin;
 RESET enable_nestloop;
 
+-- test default partition behavior for range, partition-wise join is not
+-- possible since more than one partition on one side matches default partition
+-- on the other side. Default partition from prt1 matches default partition and
+-- prt2_p4 from prt2 and default partition from prt2 matches default partition
+-- and prt1_p0 from prt1
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+
+-- partition-wise join should be possible when we drop the first and last
+-- partitions from both sides
+ALTER TABLE prt1 DETACH PARTITION prt1_p0;
+ALTER TABLE prt1 DETACH PARTITION prt1_p4;
+ANALYZE prt1;
+ALTER TABLE prt2 DETACH PARTITION prt2_p0;
+ALTER TABLE prt2 DETACH PARTITION prt2_p4;
+ANALYZE prt2;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+
+-- restore the partitioned tables for rest of the tests
+ALTER TABLE prt1 ATTACH PARTITION prt1_p0 FOR VALUES FROM (MINVALUE) TO (0);
+ALTER TABLE prt1 ATTACH PARTITION prt1_p4 FOR VALUES FROM (600) TO (800);
+ALTER TABLE prt1 DETACH PARTITION prt1_p3;
+ALTER TABLE prt1 ATTACH PARTITION prt1_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt1;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p0 FOR VALUES FROM (-250) TO (0);
+ALTER TABLE prt2 ATTACH PARTITION prt2_p4 FOR VALUES FROM (600) TO (MAXVALUE);
+ALTER TABLE prt2 DETACH PARTITION prt2_p3;
+ALTER TABLE prt2 ATTACH PARTITION prt2_p3 FOR VALUES FROM (500) TO (600);
+ANALYZE prt2;
+
+-- Add an extra partition to prt2 , Partition-wise join is possible with
+-- extra partitions on inner side are allowed
+DROP TABLE prt2_p4;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (800);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (800) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999) i WHERE i % 3 = 0;
+ANALYZE prt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- 3-way join when not every pair of joining relation can use partition-wise
+-- join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+SELECT t1.a, t2.a, t3.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON (t1.a = t2.b) INNER JOIN prt1 t3 ON (t2.b = t3.a) WHERE t2.a = 0 ORDER BY t1.a, t2.a, t3.c;
+
+-- partition-wise join can not handle missing partition on the inner side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.b;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE coalesce(t1.b, 0) + coalesce(t2.a, 0) = 0 ORDER BY t1.a, t2.a;
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE prt2_p4;
+DROP TABLE prt2_p5;
+CREATE TABLE prt2_p4 PARTITION OF prt2 FOR VALUES FROM (600) TO (700);
+CREATE TABLE prt2_p5 PARTITION OF prt2 FOR VALUES FROM (700) TO (1000);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(600, 999, 3) i;
+ANALYZE prt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 INNER JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM prt1 t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b + t2.a = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt1 t1 where not exists (select 1 from prt2 t2 WHERE t1.a = t2.b) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from prt2 t1 where not exists (select 1 from prt1 t2 WHERE t1.b = t2.a) and t1.a = 0 order by t1.a, t1.b, t1.c;
+
 --
 -- partitioned by multiple columns
 --
@@ -193,28 +347,79 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_m WHERE prt1_m.c = 0) t1
 --
 -- 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;
+\set part_mod 17
+\set cond_mod 47
+\set num_rows 500
+
+CREATE TABLE plt1 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt1_p1 PARTITION OF plt1 FOR VALUES IN ('0001','0002','0003');
+CREATE TABLE plt1_p2 PARTITION OF plt1 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN ('0008','0009');
+CREATE TABLE plt1_p4 PARTITION OF plt1 FOR VALUES IN ('0000','0010');
+INSERT INTO plt1 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (7, 11, 12, 13, 14, 15, 16);
+ANALYSE plt1;
+
+-- plt2 have missing starting 0001, additional 0007, missing ending 0010
+-- and additional 0011 and 0012 bounds
+CREATE TABLE plt2 (a int, b int, c varchar) PARTITION BY LIST(c);
+CREATE TABLE plt2_p1 PARTITION OF plt2 FOR VALUES IN ('0002','0003');
+CREATE TABLE plt2_p2 PARTITION OF plt2 FOR VALUES IN ('0004','0005','0006');
+CREATE TABLE plt2_p3 PARTITION OF plt2 FOR VALUES IN ('0007','0008','0009');
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000','0011','0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 10, 13, 14, 15, 16);
+ANALYSE plt2;
+
+-- Partition-wise-join is possible with some partition bounds overlap
+-- with each other completely and some partialy for inner,left,right,
+-- full, semi and anti joins
 
-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;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
 
 --
 -- 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;
+CREATE TABLE plt1_e_p1 PARTITION OF plt1_e FOR VALUES IN ('0002', '0003');
+CREATE TABLE plt1_e_p2 PARTITION OF plt1_e FOR VALUES IN ('0004', '0005', '0006');
+CREATE TABLE plt1_e_p3 PARTITION OF plt1_e FOR VALUES IN ('0008', '0009');
+CREATE TABLE plt1_e_p4 PARTITION OF plt1_e FOR VALUES IN ('0000');
+INSERT INTO plt1_e SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod NOT IN (1, 7, 10, 11, 12, 13, 14, 15, 16);
 ANALYZE plt1_e;
 
 -- test partition matching with N-way join
@@ -222,6 +427,175 @@ EXPLAIN (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.b = t2.b AND 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.b = t2.b AND 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;
 
+-- Add an extra partition to plt2 , Partition-wise join is possible with
+-- partitions on inner side are allowed
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (13, 14);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join, partition-wise join can not handle extra partition on the outer
+-- side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt2_p5;
+CREATE TABLE plt2_p5 PARTITION OF plt2 FOR VALUES IN ('0001','0013','0014');
+INSERT INTO plt2 SELECT i, i % :cond_mod, to_char(i % :part_mod, 'FM0000') FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (1, 13, 14);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- partition have a NULL on one side, Partition-wise join is possible with
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- in this case NULL will be treated as addition partition bounds.
+DROP TABLE plt2_p5;
+DROP TABLE plt2_p4;
+CREATE TABLE plt2_p4 PARTITION OF plt2 FOR VALUES IN ('0000',NULL,'0012');
+INSERT INTO plt2 SELECT i, i % :cond_mod, case when i % :part_mod = 11 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (0,11,12);
+ANALYZE plt2;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t1.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- partition have a NULL on both side with different partition bounds w.r.t other side
+-- NULL when NULL comparision is not strict i.e. NULL=NULL allowed
+-- Partition-wise join can not handle the case when one partition from one side
+-- matches with multiple partitions on the other side
+DROP TABLE plt1_p3;
+CREATE TABLE plt1_p3 PARTITION OF plt1 FOR VALUES IN (NULL,'0008','0009');
+INSERT INTO plt1 SELECT i, i % :cond_mod, case when i % :part_mod = 7 then NULL else to_char(i % :part_mod, 'FM0000') end FROM generate_series(0, :num_rows) i WHERE i % :part_mod IN (7,8,9);
+ANALYZE plt1;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 INNER JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + t2.b = 0 ORDER BY t1.a;
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 LEFT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.b + coalesce(t2.b, 0) = 0 ORDER BY t1.a;
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + t2.b = 0 ORDER BY t2.a;
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1 t1 FULL JOIN plt2 t2 ON t1.c = t2.c WHERE coalesce(t1.b, 0) + coalesce(t2.b, 0) = 0 ORDER BY t1.a, t2.a;
+
+-- semi join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+-- anti join
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt1 t1 where not exists (select 1 from plt2 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
+EXPLAIN (COSTS OFF)
+select t1.a, t1.b, t1.c from plt2 t1 where not exists (select 1 from plt1 t2 WHERE t1.c = t2.c) and t1.b = 0 order by t1.a, t1.b, t1.c;
+
 -- joins where one of the relations is proven empty
 EXPLAIN (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;
@@ -267,27 +641,18 @@ EXPLAIN (COSTS OFF)
 SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND 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 pht1 t1, pht2 t2, pht1_e t3 WHERE t1.b = t2.b AND 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;
 
--- test default partition behavior for range
-ALTER TABLE prt1 DETACH PARTITION prt1_p3;
-ALTER TABLE prt1 ATTACH PARTITION prt1_p3 DEFAULT;
-ANALYZE prt1;
-ALTER TABLE prt2 DETACH PARTITION prt2_p3;
-ALTER TABLE prt2 ATTACH PARTITION prt2_p3 DEFAULT;
-ANALYZE prt2;
-
-EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
-
--- test default partition behavior for list
+-- test default partition behavior for list, should not use partition-wise join
+-- since default partition from one side matches multiple partitions on the
+-- other
 ALTER TABLE plt1 DETACH PARTITION plt1_p3;
 ALTER TABLE plt1 ATTACH PARTITION plt1_p3 DEFAULT;
 ANALYZE plt1;
 ALTER TABLE plt2 DETACH PARTITION plt2_p3;
 ALTER TABLE plt2 ATTACH PARTITION plt2_p3 DEFAULT;
 ANALYZE plt2;
-
 EXPLAIN (COSTS OFF)
 SELECT avg(t1.a), avg(t2.b), t1.c, t2.c FROM plt1 t1 RIGHT JOIN plt2 t2 ON t1.c = t2.c WHERE t1.a % 25 = 0 GROUP BY t1.c, t2.c ORDER BY t1.c, t2.c;
+
 --
 -- multiple levels of partitioning
 --
-- 
2.19.2


--------------060602040206030304090709--





^ permalink  raw  reply  [nested|flat] 6+ messages in thread

* [PATCH 2/3] Refactor create_limit_path() to share cost adjustment code
@ 2019-03-06 11:28 Etsuro Fujita <[email protected]>
  0 siblings, 0 replies; 6+ messages in thread

From: Etsuro Fujita @ 2019-03-06 11:28 UTC (permalink / raw)

---
 src/backend/optimizer/util/pathnode.c | 87 +++++++++++++++++----------
 src/include/optimizer/pathnode.h      |  3 +
 2 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 169e51e792..9fd0ea4aba 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3550,17 +3550,42 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 
 	/*
 	 * Adjust the output rows count and costs according to the offset/limit.
-	 * This is only a cosmetic issue if we are at top level, but if we are
-	 * building a subquery then it's important to report correct info to the
-	 * outer planner.
-	 *
-	 * When the offset or count couldn't be estimated, use 10% of the
-	 * estimated number of rows emitted from the subpath.
-	 *
-	 * XXX we don't bother to add eval costs of the offset/limit expressions
-	 * themselves to the path costs.  In theory we should, but in most cases
-	 * those expressions are trivial and it's just not worth the trouble.
 	 */
+	adjust_limit_rows_costs(&pathnode->path.rows,
+							&pathnode->path.startup_cost,
+							&pathnode->path.total_cost,
+							offset_est, count_est);
+
+	return pathnode;
+}
+
+/*
+ * adjust_limit_rows_costs
+ *	  Adjust the size and cost estimates for a LimitPath node according to the
+ *	  offset/limit.
+ *
+ * This is only a cosmetic issue if we are at top level, but if we are
+ * building a subquery then it's important to report correct info to the outer
+ * planner.
+ *
+ * When the offset or count couldn't be estimated, use 10% of the estimated
+ * number of rows emitted from the subpath.
+ *
+ * XXX we don't bother to add eval costs of the offset/limit expressions
+ * themselves to the path costs.  In theory we should, but in most cases those
+ * expressions are trivial and it's just not worth the trouble.
+ */
+void
+adjust_limit_rows_costs(double *rows,	/* in/out parameter */
+						Cost *startup_cost,	/* in/out parameter */
+						Cost *total_cost,	/* in/out parameter */
+						int64 offset_est,
+						int64 count_est)
+{
+	double		input_rows = *rows;
+	Cost		input_startup_cost = *startup_cost;
+	Cost		input_total_cost = *total_cost;
+
 	if (offset_est != 0)
 	{
 		double		offset_rows;
@@ -3568,16 +3593,16 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 		if (offset_est > 0)
 			offset_rows = (double) offset_est;
 		else
-			offset_rows = clamp_row_est(subpath->rows * 0.10);
-		if (offset_rows > pathnode->path.rows)
-			offset_rows = pathnode->path.rows;
-		if (subpath->rows > 0)
-			pathnode->path.startup_cost +=
-				(subpath->total_cost - subpath->startup_cost)
-				* offset_rows / subpath->rows;
-		pathnode->path.rows -= offset_rows;
-		if (pathnode->path.rows < 1)
-			pathnode->path.rows = 1;
+			offset_rows = clamp_row_est(input_rows * 0.10);
+		if (offset_rows > *rows)
+			offset_rows = *rows;
+		if (input_rows > 0)
+			*startup_cost +=
+				(input_total_cost - input_startup_cost)
+				* offset_rows / input_rows;
+		*rows -= offset_rows;
+		if (*rows < 1)
+			*rows = 1;
 	}
 
 	if (count_est != 0)
@@ -3587,19 +3612,17 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 		if (count_est > 0)
 			count_rows = (double) count_est;
 		else
-			count_rows = clamp_row_est(subpath->rows * 0.10);
-		if (count_rows > pathnode->path.rows)
-			count_rows = pathnode->path.rows;
-		if (subpath->rows > 0)
-			pathnode->path.total_cost = pathnode->path.startup_cost +
-				(subpath->total_cost - subpath->startup_cost)
-				* count_rows / subpath->rows;
-		pathnode->path.rows = count_rows;
-		if (pathnode->path.rows < 1)
-			pathnode->path.rows = 1;
+			count_rows = clamp_row_est(input_rows * 0.10);
+		if (count_rows > *rows)
+			count_rows = *rows;
+		if (input_rows > 0)
+			*total_cost = *startup_cost +
+				(input_total_cost - input_startup_cost)
+				* count_rows / input_rows;
+		*rows = count_rows;
+		if (*rows < 1)
+			*rows = 1;
 	}
-
-	return pathnode;
 }
 
 
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 574bb85b50..95609aad53 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -265,6 +265,9 @@ extern LimitPath *create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 				  Path *subpath,
 				  Node *limitOffset, Node *limitCount,
 				  int64 offset_est, int64 count_est);
+extern void adjust_limit_rows_costs(double *rows,
+						Cost *startup_cost, Cost *total_cost,
+						int64 offset_est, int64 count_est);
 
 extern Path *reparameterize_path(PlannerInfo *root, Path *path,
 					Relids required_outer,
-- 
2.19.2


--------------060600050702040203040200
Content-Type: text/x-patch;
 name="v5-0003-postgres_fdw-Perform-UPPERREL_FINAL-step-remotely.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="v5-0003-postgres_fdw-Perform-UPPERREL_FINAL-step-remotely.pa";
 filename*1="tch"



^ permalink  raw  reply  [nested|flat] 6+ messages in thread

* [PATCH v13 1/8] Row pattern recognition patch for raw parser.
@ 2024-01-22 09:45 Tatsuo Ishii <[email protected]>
  0 siblings, 0 replies; 6+ messages in thread

From: Tatsuo Ishii @ 2024-01-22 09:45 UTC (permalink / raw)

---
 src/backend/parser/gram.y       | 220 ++++++++++++++++++++++++++++++--
 src/include/nodes/parsenodes.h  |  57 +++++++++
 src/include/parser/kwlist.h     |   8 ++
 src/include/parser/parse_node.h |   1 +
 4 files changed, 275 insertions(+), 11 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3460fea56b..84eb88ac2a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -660,6 +660,21 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 				json_object_constructor_null_clause_opt
 				json_array_constructor_null_clause_opt
 
+%type <target>	row_pattern_measure_item
+				row_pattern_definition
+%type <node>	opt_row_pattern_common_syntax
+				opt_row_pattern_skip_to
+				row_pattern_subset_item
+				row_pattern_term
+%type <list>	opt_row_pattern_measures
+				row_pattern_measure_list
+				row_pattern_definition_list
+				opt_row_pattern_subset_clause
+				row_pattern_subset_list
+				row_pattern_subset_rhs
+				row_pattern
+%type <boolean>	opt_row_pattern_initial_or_seek
+				first_or_last
 
 /*
  * Non-keyword token types.  These are hard-wired into the "flex" lexer.
@@ -703,7 +718,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
 
 	DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
-	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
+	DEFERRABLE DEFERRED DEFINE DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
 	DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
 	DOUBLE_P DROP
 
@@ -719,7 +734,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	HANDLER HAVING HEADER_P HOLD HOUR_P
 
 	IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE
-	INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
+	INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIAL INITIALLY INLINE_P
 	INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
 	INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
 
@@ -732,7 +747,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
 	LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
 
-	MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD
+	MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MEASURES MERGE METHOD
 	MINUTE_P MINVALUE MODE MONTH_P MOVE
 
 	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE
@@ -744,8 +759,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	ORDER ORDINALITY OTHERS OUT_P OUTER_P
 	OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER
 
-	PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD
-	PLACING PLANS POLICY
+	PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PAST
+	PATTERN_P PERMUTE PLACING PLANS POLICY
 	POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
 	PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
 
@@ -756,12 +771,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
 	ROUTINE ROUTINES ROW ROWS RULE
 
-	SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT
+	SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SEEK SELECT
 	SEQUENCE SEQUENCES
+
 	SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
 	SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
 	START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P
-	SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER
+	SUBSCRIPTION SUBSET SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER
 
 	TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN
 	TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM
@@ -867,6 +883,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	UNBOUNDED		/* ideally would have same precedence as IDENT */
 %nonassoc	IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
 			SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT
+			MEASURES AFTER INITIAL SEEK PATTERN_P
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
@@ -15928,7 +15945,8 @@ over_clause: OVER window_specification
 		;
 
 window_specification: '(' opt_existing_window_name opt_partition_clause
-						opt_sort_clause opt_frame_clause ')'
+						opt_sort_clause opt_row_pattern_measures opt_frame_clause
+						opt_row_pattern_common_syntax ')'
 				{
 					WindowDef  *n = makeNode(WindowDef);
 
@@ -15936,10 +15954,12 @@ window_specification: '(' opt_existing_window_name opt_partition_clause
 					n->refname = $2;
 					n->partitionClause = $3;
 					n->orderClause = $4;
+					n->rowPatternMeasures = $5;
 					/* copy relevant fields of opt_frame_clause */
-					n->frameOptions = $5->frameOptions;
-					n->startOffset = $5->startOffset;
-					n->endOffset = $5->endOffset;
+					n->frameOptions = $6->frameOptions;
+					n->startOffset = $6->startOffset;
+					n->endOffset = $6->endOffset;
+					n->rpCommonSyntax = (RPCommonSyntax *)$7;
 					n->location = @1;
 					$$ = n;
 				}
@@ -15963,6 +15983,31 @@ opt_partition_clause: PARTITION BY expr_list		{ $$ = $3; }
 			| /*EMPTY*/								{ $$ = NIL; }
 		;
 
+/*
+ * ROW PATTERN_P MEASURES
+ */
+opt_row_pattern_measures: MEASURES row_pattern_measure_list	{ $$ = $2; }
+			| /*EMPTY*/								{ $$ = NIL; }
+		;
+
+row_pattern_measure_list:
+			row_pattern_measure_item
+					{ $$ = list_make1($1); }
+			| row_pattern_measure_list ',' row_pattern_measure_item
+					{ $$ = lappend($1, $3); }
+		;
+
+row_pattern_measure_item:
+			a_expr AS ColLabel
+				{
+					$$ = makeNode(ResTarget);
+					$$->name = $3;
+					$$->indirection = NIL;
+					$$->val = (Node *) $1;
+					$$->location = @1;
+				}
+		;
+
 /*
  * For frame clauses, we return a WindowDef, but only some fields are used:
  * frameOptions, startOffset, and endOffset.
@@ -16122,6 +16167,143 @@ opt_window_exclusion_clause:
 			| /*EMPTY*/				{ $$ = 0; }
 		;
 
+opt_row_pattern_common_syntax:
+opt_row_pattern_skip_to opt_row_pattern_initial_or_seek
+				PATTERN_P '(' row_pattern ')'
+				opt_row_pattern_subset_clause
+				DEFINE row_pattern_definition_list
+			{
+				RPCommonSyntax *n = makeNode(RPCommonSyntax);
+				n->rpSkipTo = ((RPCommonSyntax *)$1)->rpSkipTo;
+				n->rpSkipVariable = ((RPCommonSyntax *)$1)->rpSkipVariable;
+				n->initial = $2;
+				n->rpPatterns = $5;
+				n->rpSubsetClause = $7;
+				n->rpDefs = $9;
+				$$ = (Node *) n;
+			}
+			| /*EMPTY*/		{ $$ = NULL; }
+	;
+
+opt_row_pattern_skip_to:
+			AFTER MATCH SKIP TO NEXT ROW
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					n->rpSkipTo = ST_NEXT_ROW;
+					n->rpSkipVariable = NULL;
+					$$ = (Node *) n;
+			}
+			| AFTER MATCH SKIP PAST LAST_P ROW
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					n->rpSkipTo = ST_PAST_LAST_ROW;
+					n->rpSkipVariable = NULL;
+					$$ = (Node *) n;
+				}
+			| AFTER MATCH SKIP TO first_or_last ColId
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					n->rpSkipTo = $5? ST_FIRST_VARIABLE : ST_LAST_VARIABLE;
+					n->rpSkipVariable = $6;
+					$$ = (Node *) n;
+				}
+/*
+			| AFTER MATCH SKIP TO LAST_P ColId		%prec LAST_P
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					n->rpSkipTo = ST_LAST_VARIABLE;
+					n->rpSkipVariable = $6;
+					$$ = n;
+				}
+			| AFTER MATCH SKIP TO ColId
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					n->rpSkipTo = ST_VARIABLE;
+					n->rpSkipVariable = $5;
+					$$ = n;
+				}
+*/
+			| /*EMPTY*/
+				{
+					RPCommonSyntax *n = makeNode(RPCommonSyntax);
+					/* temporary set default to ST_NEXT_ROW */
+					n->rpSkipTo = ST_PAST_LAST_ROW;
+					n->rpSkipVariable = NULL;
+					$$ = (Node *) n;
+				}
+	;
+
+first_or_last:
+			FIRST_P		{ $$ = true; }
+			| LAST_P	{ $$ = false; }
+	;
+
+opt_row_pattern_initial_or_seek:
+			INITIAL			{ $$ = true; }
+			| SEEK
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("SEEK is not supported"),
+							 errhint("Use INITIAL."),
+							 parser_errposition(@1)));
+				}
+			| /*EMPTY*/		{ $$ = true; }
+		;
+
+row_pattern:
+			row_pattern_term							{ $$ = list_make1($1); }
+			| row_pattern row_pattern_term				{ $$ = lappend($1, $2); }
+		;
+
+row_pattern_term:
+			ColId	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "", (Node *)makeString($1), NULL, @1); }
+			| ColId '*'	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *)makeString($1), NULL, @1); }
+			| ColId '+'	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *)makeString($1), NULL, @1); }
+			| ColId '?'	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "?", (Node *)makeString($1), NULL, @1); }
+		;
+
+opt_row_pattern_subset_clause:
+			SUBSET row_pattern_subset_list	{ $$ = $2; }
+			| /*EMPTY*/												{ $$ = NIL; }
+		;
+
+row_pattern_subset_list:
+			row_pattern_subset_item									{ $$ = list_make1($1); }
+			| row_pattern_subset_list ',' row_pattern_subset_item	{ $$ = lappend($1, $3); }
+			| /*EMPTY*/												{ $$ = NIL; }
+		;
+
+row_pattern_subset_item: ColId '=' '(' row_pattern_subset_rhs ')'
+			{
+				RPSubsetItem *n = makeNode(RPSubsetItem);
+				n->name = $1;
+				n->rhsVariable = $4;
+				$$ = (Node *) n;
+			}
+		;
+
+row_pattern_subset_rhs:
+			ColId								{ $$ = list_make1(makeStringConst($1, @1)); }
+			| row_pattern_subset_rhs ',' ColId	{ $$ = lappend($1, makeStringConst($3, @1)); }
+			| /*EMPTY*/							{ $$ = NIL; }
+		;
+
+row_pattern_definition_list:
+			row_pattern_definition										{ $$ = list_make1($1); }
+			| row_pattern_definition_list ',' row_pattern_definition	{ $$ = lappend($1, $3); }
+		;
+
+row_pattern_definition:
+			ColId AS a_expr
+				{
+					$$ = makeNode(ResTarget);
+					$$->name = $1;
+					$$->indirection = NIL;
+					$$->val = (Node *) $3;
+					$$->location = @1;
+				}
+		;
 
 /*
  * Supporting nonterminals for expressions.
@@ -17250,6 +17432,7 @@ unreserved_keyword:
 			| INDEXES
 			| INHERIT
 			| INHERITS
+			| INITIAL
 			| INLINE_P
 			| INPUT_P
 			| INSENSITIVE
@@ -17277,6 +17460,7 @@ unreserved_keyword:
 			| MATCHED
 			| MATERIALIZED
 			| MAXVALUE
+			| MEASURES
 			| MERGE
 			| METHOD
 			| MINUTE_P
@@ -17319,6 +17503,9 @@ unreserved_keyword:
 			| PARTITION
 			| PASSING
 			| PASSWORD
+			| PAST
+			| PATTERN_P
+			| PERMUTE
 			| PLANS
 			| POLICY
 			| PRECEDING
@@ -17369,6 +17556,7 @@ unreserved_keyword:
 			| SEARCH
 			| SECOND_P
 			| SECURITY
+			| SEEK
 			| SEQUENCE
 			| SEQUENCES
 			| SERIALIZABLE
@@ -17394,6 +17582,7 @@ unreserved_keyword:
 			| STRICT_P
 			| STRIP_P
 			| SUBSCRIPTION
+			| SUBSET
 			| SUPPORT
 			| SYSID
 			| SYSTEM_P
@@ -17581,6 +17770,7 @@ reserved_keyword:
 			| CURRENT_USER
 			| DEFAULT
 			| DEFERRABLE
+			| DEFINE
 			| DESC
 			| DISTINCT
 			| DO
@@ -17743,6 +17933,7 @@ bare_label_keyword:
 			| DEFAULTS
 			| DEFERRABLE
 			| DEFERRED
+			| DEFINE
 			| DEFINER
 			| DELETE_P
 			| DELIMITER
@@ -17818,6 +18009,7 @@ bare_label_keyword:
 			| INDEXES
 			| INHERIT
 			| INHERITS
+			| INITIAL
 			| INITIALLY
 			| INLINE_P
 			| INNER_P
@@ -17867,6 +18059,7 @@ bare_label_keyword:
 			| MATCHED
 			| MATERIALIZED
 			| MAXVALUE
+			| MEASURES
 			| MERGE
 			| METHOD
 			| MINVALUE
@@ -17920,6 +18113,9 @@ bare_label_keyword:
 			| PARTITION
 			| PASSING
 			| PASSWORD
+			| PAST
+			| PATTERN_P
+			| PERMUTE
 			| PLACING
 			| PLANS
 			| POLICY
@@ -17976,6 +18172,7 @@ bare_label_keyword:
 			| SCROLL
 			| SEARCH
 			| SECURITY
+			| SEEK
 			| SELECT
 			| SEQUENCE
 			| SEQUENCES
@@ -18007,6 +18204,7 @@ bare_label_keyword:
 			| STRICT_P
 			| STRIP_P
 			| SUBSCRIPTION
+			| SUBSET
 			| SUBSTRING
 			| SUPPORT
 			| SYMMETRIC
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b3181f34ae..64e9df0a48 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -540,6 +540,44 @@ typedef struct SortBy
 	int			location;		/* operator location, or -1 if none/unknown */
 } SortBy;
 
+/*
+ * AFTER MATCH row pattern skip to types in row pattern common syntax
+ */
+typedef enum RPSkipTo
+{
+	ST_NONE,					/* AFTER MATCH omitted */
+	ST_NEXT_ROW,				/* SKIP TO NEXT ROW */
+	ST_PAST_LAST_ROW,			/* SKIP TO PAST LAST ROW */
+	ST_FIRST_VARIABLE,			/* SKIP TO FIRST variable name */
+	ST_LAST_VARIABLE,			/* SKIP TO LAST variable name */
+	ST_VARIABLE					/* SKIP TO variable name */
+} RPSkipTo;
+
+/*
+ * Row Pattern SUBSET clause item
+ */
+typedef struct RPSubsetItem
+{
+	NodeTag		type;
+	char	   *name;			/* Row Pattern SUBSET clause variable name */
+	List	   *rhsVariable;	/* Row Pattern SUBSET rhs variables (list of char *string) */
+} RPSubsetItem;
+
+/*
+ * RowPatternCommonSyntax - raw representation of row pattern common syntax
+ *
+ */
+typedef struct RPCommonSyntax
+{
+	NodeTag		type;
+	RPSkipTo	rpSkipTo;		/* Row Pattern AFTER MATCH SKIP type */
+	char	   *rpSkipVariable;	/* Row Pattern Skip To variable name, if any */
+	bool		initial;		/* true if <row pattern initial or seek> is initial */
+	List	   *rpPatterns;		/* PATTERN variables (list of A_Expr) */
+	List	   *rpSubsetClause;	/* row pattern subset clause (list of RPSubsetItem), if any */
+	List	   *rpDefs;			/* row pattern definitions clause (list of ResTarget) */
+} RPCommonSyntax;
+
 /*
  * WindowDef - raw representation of WINDOW and OVER clauses
  *
@@ -555,6 +593,8 @@ typedef struct WindowDef
 	char	   *refname;		/* referenced window name, if any */
 	List	   *partitionClause;	/* PARTITION BY expression list */
 	List	   *orderClause;	/* ORDER BY (list of SortBy) */
+	List	   *rowPatternMeasures;	/* row pattern measures (list of ResTarget) */
+	RPCommonSyntax *rpCommonSyntax;	/* row pattern common syntax */
 	int			frameOptions;	/* frame_clause options, see below */
 	Node	   *startOffset;	/* expression for starting bound, if any */
 	Node	   *endOffset;		/* expression for ending bound, if any */
@@ -1476,6 +1516,11 @@ typedef struct GroupingSet
  * the orderClause might or might not be copied (see copiedOrder); the framing
  * options are never copied, per spec.
  *
+ * "defineClause" is Row Pattern Recognition DEFINE clause (list of
+ * TargetEntry). TargetEntry.resname represents row pattern definition
+ * variable name. "patternVariable" and "patternRegexp" represents PATTERN
+ * clause.
+ *
  * The information relevant for the query jumbling is the partition clause
  * type and its bounds.
  */
@@ -1507,6 +1552,18 @@ typedef struct WindowClause
 	Index		winref;			/* ID referenced by window functions */
 	/* did we copy orderClause from refname? */
 	bool		copiedOrder pg_node_attr(query_jumble_ignore);
+	/* Row Pattern AFTER MACH SKIP clause */
+	RPSkipTo	rpSkipTo;		/* Row Pattern Skip To type */
+	char        *rpSkipVariable;/* Row Pattern Skip To variable */
+	bool		initial;		/* true if <row pattern initial or seek> is initial */
+	/* Row Pattern DEFINE clause (list of TargetEntry) */
+	List		*defineClause;
+	/* Row Pattern DEFINE variable initial names (list of String) */
+	List		*defineInitial;
+	/* Row Pattern PATTERN variable name (list of String) */
+	List		*patternVariable;
+	/* Row Pattern PATTERN regular expression quantifier ('+' or ''. list of String) */
+	List		*patternRegexp;
 } WindowClause;
 
 /*
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 2331acac09..6b3734a865 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -128,6 +128,7 @@ PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("define", DEFINE, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL)
@@ -212,6 +213,7 @@ PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("initial", INITIAL, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
@@ -265,6 +267,7 @@ PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("measures", MEASURES, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL)
@@ -326,6 +329,9 @@ PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("past", PAST, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("pattern", PATTERN_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("permute", PERMUTE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL)
@@ -385,6 +391,7 @@ PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL)
 PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("seek", SEEK, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL)
@@ -416,6 +423,7 @@ PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("subset", SUBSET, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL)
 PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL)
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 99d6515736..1e43cef6f4 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -51,6 +51,7 @@ typedef enum ParseExprKind
 	EXPR_KIND_WINDOW_FRAME_RANGE,	/* window frame clause with RANGE */
 	EXPR_KIND_WINDOW_FRAME_ROWS,	/* window frame clause with ROWS */
 	EXPR_KIND_WINDOW_FRAME_GROUPS,	/* window frame clause with GROUPS */
+	EXPR_KIND_RPR_DEFINE,		/* DEFINE */
 	EXPR_KIND_SELECT_TARGET,	/* SELECT target list item */
 	EXPR_KIND_INSERT_TARGET,	/* INSERT target list item */
 	EXPR_KIND_UPDATE_SOURCE,	/* UPDATE assignment source item */
-- 
2.25.1


----Next_Part(Mon_Jan_22_19_26_18_2024_011)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="v13-0002-Row-pattern-recognition-patch-parse-analysis.patch"



^ permalink  raw  reply  [nested|flat] 6+ messages in thread

* Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions
@ 2024-10-17 06:07 jian he <[email protected]>
  2024-10-17 13:59 ` Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions Bruce Momjian <[email protected]>
  0 siblings, 1 reply; 6+ messages in thread

From: jian he @ 2024-10-17 06:07 UTC (permalink / raw)
  To: Bruce Momjian <[email protected]>; +Cc: David G. Johnston <[email protected]>; pgsql-hackers

On Thu, Oct 17, 2024 at 7:59 AM Bruce Momjian <[email protected]> wrote:
>
>
> Where are we on this?  I still see this behavior.
>
> ---------------------------------------------------------------------------

> > but I found following two examples returning different results,
> > i think they should return the same value.
> > select json_value('1', '$ == "1"' returning jsonb error on error);
> > select json_query('1', '$ == "1"' returning jsonb error on error);

This part has been resolved.
see section Note section in
https://www.postgresql.org/docs/current/functions-json.html#SQLJSON-QUERY-FUNCTIONS


>
> On Fri, Jun 21, 2024 at 04:53:55PM +0800, jian he wrote:
> > On Fri, Jun 21, 2024 at 11:11 AM David G. Johnston
> > <[email protected]> wrote:
> > >
> > > On Thu, Jun 20, 2024 at 7:30 PM jian he <[email protected]> wrote:
> > >>
> > >> "predicate check expressions return the single three-valued result of
> > >>
> > >> the predicate: true, false, or unknown."
> > >> "unknown" is wrong, because `select 'unknown'::jsonb;` will fail.
> > >> here "unknown" should be "null"? see jsonb_path_query doc entry also.
> > >>

doc (https://www.postgresql.org/docs/devel/functions-json.html#FUNCTIONS-SQLJSON-CHECK-EXPRESSIONS)
<<QUOTE>>
While SQL-standard path expressions return the relevant element(s) of
the queried JSON value, predicate check expressions return the single
three-valued result of the predicate: true, false, or unknown.
<<END OF QUOTE>>

https://www.postgresql.org/docs/current/datatype-boolean.html
says
"The boolean type can have several states: “true”, “false”, and a
third state, “unknown”, which is represented by the SQL null value."

but here
select jsonb_path_query('1', '$ == "a"');
return JSON null value, not SQL null value.

however.
select jsonb_path_match('1', '$ == "a"');
return SQL null value.


maybe we can change to
"predicate check expressions return the single three-valued result of
the predicate: true, false, or null"

Then in the <note> section mention that
when Predicate check expressions cannot be applied, it returns JSON
null for function jsonb_path_query,
return SQL NULL for function jsonb_path_match or @@ operator.






^ permalink  raw  reply  [nested|flat] 6+ messages in thread

* Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions
  2024-10-17 06:07 Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions jian he <[email protected]>
@ 2024-10-17 13:59 ` Bruce Momjian <[email protected]>
  0 siblings, 0 replies; 6+ messages in thread

From: Bruce Momjian @ 2024-10-17 13:59 UTC (permalink / raw)
  To: jian he <[email protected]>; +Cc: David G. Johnston <[email protected]>; pgsql-hackers

On Thu, Oct 17, 2024 at 02:07:00PM +0800, jian he wrote:
> On Thu, Oct 17, 2024 at 7:59 AM Bruce Momjian <[email protected]> wrote:
> >
> >
> > Where are we on this?  I still see this behavior.
> >
> > ---------------------------------------------------------------------------
> 
> > > but I found following two examples returning different results,
> > > i think they should return the same value.
> > > select json_value('1', '$ == "1"' returning jsonb error on error);
> > > select json_query('1', '$ == "1"' returning jsonb error on error);
> 
> This part has been resolved.
> see section Note section in
> https://www.postgresql.org/docs/current/functions-json.html#SQLJSON-QUERY-FUNCTIONS

Okay, good.

> > > >> the predicate: true, false, or unknown."
> > > >> "unknown" is wrong, because `select 'unknown'::jsonb;` will fail.
> > > >> here "unknown" should be "null"? see jsonb_path_query doc entry also.
> > > >>
> 
> doc (https://www.postgresql.org/docs/devel/functions-json.html#FUNCTIONS-SQLJSON-CHECK-EXPRESSIONS)
> <<QUOTE>>
> While SQL-standard path expressions return the relevant element(s) of
> the queried JSON value, predicate check expressions return the single
> three-valued result of the predicate: true, false, or unknown.
> <<END OF QUOTE>>
> 
> https://www.postgresql.org/docs/current/datatype-boolean.html
> says
> "The boolean type can have several states: “true”, “false”, and a
> third state, “unknown”, which is represented by the SQL null value."
> 
> but here
> select jsonb_path_query('1', '$ == "a"');
> return JSON null value, not SQL null value.
> 
> however.
> select jsonb_path_match('1', '$ == "a"');
> return SQL null value.
> 
> 
> maybe we can change to
> "predicate check expressions return the single three-valued result of
> the predicate: true, false, or null"

Yes, done in the attached patch.

> Then in the <note> section mention that
> when Predicate check expressions cannot be applied, it returns JSON
> null for function jsonb_path_query,
> return SQL NULL for function jsonb_path_match or @@ operator.

The section is titled, "9.16.2.1. Deviations from the SQL Standard".  Is
this a deviation from the standard?  If not, I think we have to
distinguish SQL null and JSON null somewhere else.  Is the "Note" text
also a deviation?

-- 
  Bruce Momjian  <[email protected]>        https://momjian.us
  EDB                                      https://enterprisedb.com

  When a patient asks the doctor, "Am I going to die?", he means 
  "Am I going to die soon?"


Attachments:

  [text/x-diff] json.diff (681B, ../../[email protected]/2-json.diff)
  download | inline diff:
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f8a0d76d12b..bf35145de89 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17648,7 +17648,7 @@ SELECT '{
      element(s) of the queried JSON value, predicate check expressions
      return the single three-valued result of the
      predicate: <literal>true</literal>,
-     <literal>false</literal>, or <literal>unknown</literal>.
+     <literal>false</literal>, or <literal>NULL</literal>.
      For example, we could write this SQL-standard filter expression:
 <screen>
 <prompt>=&gt;</prompt> <userinput>select jsonb_path_query(:'json', '$.track.segments ?(@[*].HR &gt; 130)');</userinput>


^ permalink  raw  reply  [nested|flat] 6+ messages in thread


end of thread, other threads:[~2024-10-17 13:59 UTC | newest]

Thread overview: 6+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-01-22 12:28 [PATCH 3/3] Tests for 0:1, 1:1 and 1:0 partition matching Etsuro Fujita <[email protected]>
2019-01-31 11:31 [PATCH 3/3] Tests for 0:1, 1:1 and 1:0 partition matching Etsuro Fujita <[email protected]>
2019-03-06 11:28 [PATCH 2/3] Refactor create_limit_path() to share cost adjustment code Etsuro Fujita <[email protected]>
2024-01-22 09:45 [PATCH v13 1/8] Row pattern recognition patch for raw parser. Tatsuo Ishii <[email protected]>
2024-10-17 06:07 Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions jian he <[email protected]>
2024-10-17 13:59 ` Re: minor doc issue in 9.16.2.1.1. Boolean Predicate Check Expressions Bruce Momjian <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox