summaryrefslogtreecommitdiffstats
path: root/src/test/regress/expected/partition_join.out
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/regress/expected/partition_join.out')
-rw-r--r--src/test/regress/expected/partition_join.out4912
1 files changed, 4912 insertions, 0 deletions
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
new file mode 100644
index 0000000..bb5b7c4
--- /dev/null
+++ b/src/test/regress/expected/partition_join.out
@@ -0,0 +1,4912 @@
+--
+-- PARTITION_JOIN
+-- Test partitionwise join between partitioned tables
+--
+-- Enable partitionwise join, which by default is disabled.
+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_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 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);
+ANALYZE prt1;
+CREATE TABLE prt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_p1 PARTITION OF prt2 FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_p2 PARTITION OF prt2 FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_p3 PARTITION OF prt2 FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(0, 599) i WHERE i % 3 = 0;
+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);
+ANALYZE prt2;
+-- 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
+--------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> 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)
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_p3 t1_3
+ Filter: (b = 0)
+(21 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)
+
+-- left outer join, with whole-row reference; partitionwise join does not apply
+EXPLAIN (COSTS OFF)
+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;
+ QUERY PLAN
+--------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Hash Right Join
+ Hash Cond: (t2.b = t1.a)
+ -> Append
+ -> Seq Scan on prt2_p1 t2_1
+ -> Seq Scan on prt2_p2 t2_2
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Append
+ -> 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)
+(16 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)
+
+-- right outer join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+---------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> 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_2
+ Filter: (a = 0)
+ -> Nested Loop Left Join
+ -> 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)
+(20 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)
+
+-- full outer join, with placeholder vars
+EXPLAIN (COSTS OFF)
+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;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: prt1.a, prt2.b
+ -> Append
+ -> Hash Full Join
+ Hash Cond: (prt1_1.a = prt2_1.b)
+ Filter: (((50) = prt1_1.a) OR ((75) = prt2_1.b))
+ -> Seq Scan on prt1_p1 prt1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p1 prt2_1
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: (prt1_2.a = prt2_2.b)
+ Filter: (((50) = prt1_2.a) OR ((75) = prt2_2.b))
+ -> Seq Scan on prt1_p2 prt1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p2 prt2_2
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: (prt1_3.a = prt2_3.b)
+ Filter: (((50) = prt1_3.a) OR ((75) = prt2_3.b))
+ -> Seq Scan on prt1_p3 prt1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p3 prt2_3
+ Filter: (a = 0)
+(27 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
+----+------+----+------
+ 50 | 0050 | |
+ | | 75 | 0075
+(2 rows)
+
+-- Join with pruned partitions from joining relations
+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 < 450 AND t2.b > 250 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)
+ -> Seq Scan on prt2_p2 t2
+ Filter: (b > 250)
+ -> Hash
+ -> Seq Scan on prt1_p2 t1
+ Filter: ((a < 450) AND (b = 0))
+(9 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 300 | 0300 | 300 | 0300
+(1 row)
+
+-- Currently we can't do partitioned join if nullable-side partitions are pruned
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+-----------------------------------------------------------
+ Sort
+ Sort Key: prt1.a, prt2.b
+ -> Hash Right Join
+ Hash Cond: (prt2.b = prt1.a)
+ -> Append
+ -> Seq Scan on prt2_p2 prt2_1
+ Filter: (b > 250)
+ -> Seq Scan on prt2_p3 prt2_2
+ Filter: (b > 250)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_p1 prt1_1
+ Filter: ((a < 450) AND (b = 0))
+ -> Seq Scan on prt1_p2 prt1_2
+ Filter: ((a < 450) AND (b = 0))
+(15 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)
+
+-- Currently we can't do partitioned join if nullable-side partitions are pruned
+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.a, prt2.b
+ -> Hash Full Join
+ Hash Cond: (prt1.a = prt2.b)
+ Filter: ((prt1.b = 0) OR (prt2.a = 0))
+ -> Append
+ -> Seq Scan on prt1_p1 prt1_1
+ Filter: (a < 450)
+ -> Seq Scan on prt1_p2 prt1_2
+ Filter: (a < 450)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_p2 prt2_1
+ Filter: (b > 250)
+ -> Seq Scan on prt2_p3 prt2_2
+ Filter: (b > 250)
+(16 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)
+
+-- 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
+--------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> 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
+ Filter: (a = 0)
+ -> 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
+ Filter: (a = 0)
+ -> Nested Loop Semi Join
+ Join Filter: (t1_3.a = t2_3.b)
+ -> Seq Scan on prt1_p3 t1_3
+ Filter: (b = 0)
+ -> Materialize
+ -> Seq Scan on prt2_p3 t2_3
+ Filter: (a = 0)
+(24 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)
+
+-- 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);
+ QUERY PLAN
+--------------------------------------------------
+ Aggregate
+ -> Append
+ -> Hash Anti Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> Seq Scan on prt1_p1 t1_1
+ -> 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
+ -> Hash
+ -> 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
+(17 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
+(1 row)
+
+-- lateral reference
+EXPLAIN (COSTS OFF)
+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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Left Join
+ -> Seq Scan on prt1_p1 t1_1
+ Filter: (b = 0)
+ -> Nested Loop
+ -> Index Only Scan using iprt1_p1_a on prt1_p1 t2_1
+ Index Cond: (a = t1_1.a)
+ -> 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_p2 t1_2
+ Filter: (b = 0)
+ -> Nested Loop
+ -> Index Only Scan using iprt1_p2_a on prt1_p2 t2_2
+ Index Cond: (a = t1_2.a)
+ -> Index Scan using iprt2_p2_b on prt2_p2 t3_2
+ Index Cond: (b = t2_2.a)
+ -> 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)
+(27 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)
+
+EXPLAIN (COSTS OFF)
+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.b) 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;
+ 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 prt1_p1 t1_1
+ -> Seq Scan on prt1_p2 t1_2
+ -> Seq Scan on prt1_p3 t1_3
+ -> Hash
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.a = t3_1.b)
+ -> Seq Scan on prt1_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt2_p1 t3_1
+ -> Hash Join
+ Hash Cond: (t2_2.a = t3_2.b)
+ -> Seq Scan on prt1_p2 t2_2
+ -> Hash
+ -> 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
+(26 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)
+
+-- bug with inadequate sort key representation
+SET enable_partitionwise_aggregate TO true;
+SET enable_hashjoin TO false;
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b)
+ WHERE a BETWEEN 490 AND 510
+ GROUP BY 1, 2 ORDER BY 1, 2;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------
+ Group
+ Group Key: (COALESCE(prt1.a, p2.a)), (COALESCE(prt1.b, p2.b))
+ -> Merge Append
+ Sort Key: (COALESCE(prt1.a, p2.a)), (COALESCE(prt1.b, p2.b))
+ -> Group
+ Group Key: (COALESCE(prt1.a, p2.a)), (COALESCE(prt1.b, p2.b))
+ -> Sort
+ Sort Key: (COALESCE(prt1.a, p2.a)), (COALESCE(prt1.b, p2.b))
+ -> Merge Full Join
+ Merge Cond: ((prt1.a = p2.a) AND (prt1.b = p2.b))
+ Filter: ((COALESCE(prt1.a, p2.a) >= 490) AND (COALESCE(prt1.a, p2.a) <= 510))
+ -> Sort
+ Sort Key: prt1.a, prt1.b
+ -> Seq Scan on prt1_p1 prt1
+ -> Sort
+ Sort Key: p2.a, p2.b
+ -> Seq Scan on prt2_p1 p2
+ -> Group
+ Group Key: (COALESCE(prt1_1.a, p2_1.a)), (COALESCE(prt1_1.b, p2_1.b))
+ -> Sort
+ Sort Key: (COALESCE(prt1_1.a, p2_1.a)), (COALESCE(prt1_1.b, p2_1.b))
+ -> Merge Full Join
+ Merge Cond: ((prt1_1.a = p2_1.a) AND (prt1_1.b = p2_1.b))
+ Filter: ((COALESCE(prt1_1.a, p2_1.a) >= 490) AND (COALESCE(prt1_1.a, p2_1.a) <= 510))
+ -> Sort
+ Sort Key: prt1_1.a, prt1_1.b
+ -> Seq Scan on prt1_p2 prt1_1
+ -> Sort
+ Sort Key: p2_1.a, p2_1.b
+ -> Seq Scan on prt2_p2 p2_1
+ -> Group
+ Group Key: (COALESCE(prt1_2.a, p2_2.a)), (COALESCE(prt1_2.b, p2_2.b))
+ -> Sort
+ Sort Key: (COALESCE(prt1_2.a, p2_2.a)), (COALESCE(prt1_2.b, p2_2.b))
+ -> Merge Full Join
+ Merge Cond: ((prt1_2.a = p2_2.a) AND (prt1_2.b = p2_2.b))
+ Filter: ((COALESCE(prt1_2.a, p2_2.a) >= 490) AND (COALESCE(prt1_2.a, p2_2.a) <= 510))
+ -> Sort
+ Sort Key: prt1_2.a, prt1_2.b
+ -> Seq Scan on prt1_p3 prt1_2
+ -> Sort
+ Sort Key: p2_2.a, p2_2.b
+ -> Seq Scan on prt2_p3 p2_2
+(43 rows)
+
+SELECT a, b FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b)
+ WHERE a BETWEEN 490 AND 510
+ GROUP BY 1, 2 ORDER BY 1, 2;
+ a | b
+-----+----
+ 490 | 15
+ 492 | 17
+ 494 | 19
+ 495 | 20
+ 496 | 21
+ 498 | 23
+ 500 | 0
+ 501 | 1
+ 502 | 2
+ 504 | 4
+ 506 | 6
+ 507 | 7
+ 508 | 8
+ 510 | 10
+(14 rows)
+
+RESET enable_partitionwise_aggregate;
+RESET enable_hashjoin;
+--
+-- partitioned by expression
+--
+CREATE TABLE prt1_e (a int, b int, c int) PARTITION BY RANGE(((a + b)/2));
+CREATE TABLE prt1_e_p1 PARTITION OF prt1_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_e_p2 PARTITION OF prt1_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt1_e_p3 PARTITION OF prt1_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt1_e SELECT i, i, i % 25 FROM generate_series(0, 599, 2) i;
+CREATE INDEX iprt1_e_p1_ab2 on prt1_e_p1(((a+b)/2));
+CREATE INDEX iprt1_e_p2_ab2 on prt1_e_p2(((a+b)/2));
+CREATE INDEX iprt1_e_p3_ab2 on prt1_e_p3(((a+b)/2));
+ANALYZE prt1_e;
+CREATE TABLE prt2_e (a int, b int, c int) PARTITION BY RANGE(((b + a)/2));
+CREATE TABLE prt2_e_p1 PARTITION OF prt2_e FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_e_p2 PARTITION OF prt2_e FOR VALUES FROM (250) TO (500);
+CREATE TABLE prt2_e_p3 PARTITION OF prt2_e FOR VALUES FROM (500) TO (600);
+INSERT INTO prt2_e SELECT i, i, i % 25 FROM generate_series(0, 599, 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;
+ QUERY PLAN
+------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Join
+ Hash Cond: (((t2_1.b + t2_1.a) / 2) = ((t1_1.a + t1_1.b) / 2))
+ -> Seq Scan on prt2_e_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_e_p1 t1_1
+ Filter: (c = 0)
+ -> Hash Join
+ Hash Cond: (((t2_2.b + t2_2.a) / 2) = ((t1_2.a + t1_2.b) / 2))
+ -> Seq Scan on prt2_e_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_e_p2 t1_2
+ Filter: (c = 0)
+ -> 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)
+(21 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)
+
+--
+-- N-way join
+--
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a + t3.b, t3.c FROM prt1 t1, prt2 t2, prt1_e t3 WHERE t1.a = t2.b AND t1.a = (t3.a + t3.b)/2 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+---------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> 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_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_p1 t1_1
+ Filter: (b = 0)
+ -> Index Scan using iprt1_e_p1_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_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_p2 t1_2
+ Filter: (b = 0)
+ -> Index Scan using iprt1_e_p2_ab2 on prt1_e_p2 t3_2
+ Index Cond: (((a + b) / 2) = t2_2.b)
+ -> Nested Loop
+ Join Filter: (t1_3.a = ((t3_3.a + t3_3.b) / 2))
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_p3 t1_3
+ Filter: (b = 0)
+ -> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t3_3
+ Index Cond: (((a + b) / 2) = t2_3.b)
+(33 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)
+
+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
+--------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (((t3_1.a + t3_1.b) / 2) = t1_1.a)
+ -> Seq Scan on prt1_e_p1 t3_1
+ -> Hash
+ -> 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: (((t3_2.a + t3_2.b) / 2) = t1_2.a)
+ -> Seq Scan on prt1_e_p2 t3_2
+ -> Hash
+ -> 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)
+ -> Hash Right Join
+ Hash Cond: (((t3_3.a + t3_3.b) / 2) = t1_3.a)
+ -> Seq Scan on prt1_e_p3 t3_3
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_p3 t1_3
+ Filter: (b = 0)
+(33 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)
+
+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
+-------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+ -> Append
+ -> Nested Loop Left Join
+ -> Hash Right Join
+ Hash Cond: (t1_1.a = ((t3_1.a + t3_1.b) / 2))
+ -> Seq Scan on prt1_p1 t1_1
+ -> Hash
+ -> Seq Scan on prt1_e_p1 t3_1
+ Filter: (c = 0)
+ -> Index Scan using iprt2_p1_b on prt2_p1 t2_1
+ Index Cond: (b = t1_1.a)
+ -> Nested Loop Left Join
+ -> Hash Right Join
+ Hash Cond: (t1_2.a = ((t3_2.a + t3_2.b) / 2))
+ -> Seq Scan on prt1_p2 t1_2
+ -> Hash
+ -> Seq Scan on prt1_e_p2 t3_2
+ Filter: (c = 0)
+ -> Index Scan using iprt2_p2_b on prt2_p2 t2_2
+ Index Cond: (b = t1_2.a)
+ -> Nested Loop Left Join
+ -> Hash Right Join
+ Hash Cond: (t1_3.a = ((t3_3.a + t3_3.b) / 2))
+ -> Seq Scan on prt1_p3 t1_3
+ -> Hash
+ -> Seq Scan on prt1_e_p3 t3_3
+ Filter: (c = 0)
+ -> Index Scan using iprt2_p3_b on prt2_p3 t2_3
+ Index Cond: (b = t1_3.a)
+(30 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)
+
+--
+-- 3-way full join
+--
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b) FULL JOIN prt2 p3(b,a,c) USING (a, b)
+ WHERE a BETWEEN 490 AND 510;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_1.a, p2_1.a) = p3_1.a) AND (COALESCE(prt1_1.b, p2_1.b) = p3_1.b))
+ Filter: ((COALESCE(COALESCE(prt1_1.a, p2_1.a), p3_1.a) >= 490) AND (COALESCE(COALESCE(prt1_1.a, p2_1.a), p3_1.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((prt1_1.a = p2_1.a) AND (prt1_1.b = p2_1.b))
+ -> Seq Scan on prt1_p1 prt1_1
+ -> Hash
+ -> Seq Scan on prt2_p1 p2_1
+ -> Hash
+ -> Seq Scan on prt2_p1 p3_1
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_2.a, p2_2.a) = p3_2.a) AND (COALESCE(prt1_2.b, p2_2.b) = p3_2.b))
+ Filter: ((COALESCE(COALESCE(prt1_2.a, p2_2.a), p3_2.a) >= 490) AND (COALESCE(COALESCE(prt1_2.a, p2_2.a), p3_2.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((prt1_2.a = p2_2.a) AND (prt1_2.b = p2_2.b))
+ -> Seq Scan on prt1_p2 prt1_2
+ -> Hash
+ -> Seq Scan on prt2_p2 p2_2
+ -> Hash
+ -> Seq Scan on prt2_p2 p3_2
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_3.a, p2_3.a) = p3_3.a) AND (COALESCE(prt1_3.b, p2_3.b) = p3_3.b))
+ Filter: ((COALESCE(COALESCE(prt1_3.a, p2_3.a), p3_3.a) >= 490) AND (COALESCE(COALESCE(prt1_3.a, p2_3.a), p3_3.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((prt1_3.a = p2_3.a) AND (prt1_3.b = p2_3.b))
+ -> Seq Scan on prt1_p3 prt1_3
+ -> Hash
+ -> Seq Scan on prt2_p3 p2_3
+ -> Hash
+ -> Seq Scan on prt2_p3 p3_3
+(32 rows)
+
+SELECT COUNT(*) FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b) FULL JOIN prt2 p3(b,a,c) USING (a, b)
+ WHERE a BETWEEN 490 AND 510;
+ count
+-------
+ 14
+(1 row)
+
+--
+-- 4-way full join
+--
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b) FULL JOIN prt2 p3(b,a,c) USING (a, b) FULL JOIN prt1 p4 (a,b,c) USING (a, b)
+ WHERE a BETWEEN 490 AND 510;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(COALESCE(prt1_1.a, p2_1.a), p3_1.a) = p4_1.a) AND (COALESCE(COALESCE(prt1_1.b, p2_1.b), p3_1.b) = p4_1.b))
+ Filter: ((COALESCE(COALESCE(COALESCE(prt1_1.a, p2_1.a), p3_1.a), p4_1.a) >= 490) AND (COALESCE(COALESCE(COALESCE(prt1_1.a, p2_1.a), p3_1.a), p4_1.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_1.a, p2_1.a) = p3_1.a) AND (COALESCE(prt1_1.b, p2_1.b) = p3_1.b))
+ -> Hash Full Join
+ Hash Cond: ((prt1_1.a = p2_1.a) AND (prt1_1.b = p2_1.b))
+ -> Seq Scan on prt1_p1 prt1_1
+ -> Hash
+ -> Seq Scan on prt2_p1 p2_1
+ -> Hash
+ -> Seq Scan on prt2_p1 p3_1
+ -> Hash
+ -> Seq Scan on prt1_p1 p4_1
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(COALESCE(prt1_2.a, p2_2.a), p3_2.a) = p4_2.a) AND (COALESCE(COALESCE(prt1_2.b, p2_2.b), p3_2.b) = p4_2.b))
+ Filter: ((COALESCE(COALESCE(COALESCE(prt1_2.a, p2_2.a), p3_2.a), p4_2.a) >= 490) AND (COALESCE(COALESCE(COALESCE(prt1_2.a, p2_2.a), p3_2.a), p4_2.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_2.a, p2_2.a) = p3_2.a) AND (COALESCE(prt1_2.b, p2_2.b) = p3_2.b))
+ -> Hash Full Join
+ Hash Cond: ((prt1_2.a = p2_2.a) AND (prt1_2.b = p2_2.b))
+ -> Seq Scan on prt1_p2 prt1_2
+ -> Hash
+ -> Seq Scan on prt2_p2 p2_2
+ -> Hash
+ -> Seq Scan on prt2_p2 p3_2
+ -> Hash
+ -> Seq Scan on prt1_p2 p4_2
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(COALESCE(prt1_3.a, p2_3.a), p3_3.a) = p4_3.a) AND (COALESCE(COALESCE(prt1_3.b, p2_3.b), p3_3.b) = p4_3.b))
+ Filter: ((COALESCE(COALESCE(COALESCE(prt1_3.a, p2_3.a), p3_3.a), p4_3.a) >= 490) AND (COALESCE(COALESCE(COALESCE(prt1_3.a, p2_3.a), p3_3.a), p4_3.a) <= 510))
+ -> Hash Full Join
+ Hash Cond: ((COALESCE(prt1_3.a, p2_3.a) = p3_3.a) AND (COALESCE(prt1_3.b, p2_3.b) = p3_3.b))
+ -> Hash Full Join
+ Hash Cond: ((prt1_3.a = p2_3.a) AND (prt1_3.b = p2_3.b))
+ -> Seq Scan on prt1_p3 prt1_3
+ -> Hash
+ -> Seq Scan on prt2_p3 p2_3
+ -> Hash
+ -> Seq Scan on prt2_p3 p3_3
+ -> Hash
+ -> Seq Scan on prt1_p3 p4_3
+(44 rows)
+
+SELECT COUNT(*) FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b) FULL JOIN prt2 p3(b,a,c) USING (a, b) FULL JOIN prt1 p4 (a,b,c) USING (a, b)
+ WHERE a BETWEEN 490 AND 510;
+ count
+-------
+ 14
+(1 row)
+
+-- Cases with non-nullable expressions in subquery results;
+-- make sure these go to null as expected
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.phv, t2.b, t2.phv, t3.a + t3.b, t3.phv FROM ((SELECT 50 phv, * FROM prt1 WHERE prt1.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;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: prt1.a, prt2.b, ((prt1_e.a + prt1_e.b))
+ -> Append
+ -> Hash Full Join
+ Hash Cond: (prt1_1.a = ((prt1_e_1.a + prt1_e_1.b) / 2))
+ Filter: ((prt1_1.a = (50)) OR (prt2_1.b = (75)) OR (((prt1_e_1.a + prt1_e_1.b) / 2) = (50)))
+ -> Hash Full Join
+ Hash Cond: (prt1_1.a = prt2_1.b)
+ -> Seq Scan on prt1_p1 prt1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p1 prt2_1
+ Filter: (a = 0)
+ -> Hash
+ -> Seq Scan on prt1_e_p1 prt1_e_1
+ Filter: (c = 0)
+ -> Hash Full Join
+ Hash Cond: (prt1_2.a = ((prt1_e_2.a + prt1_e_2.b) / 2))
+ Filter: ((prt1_2.a = (50)) OR (prt2_2.b = (75)) OR (((prt1_e_2.a + prt1_e_2.b) / 2) = (50)))
+ -> Hash Full Join
+ Hash Cond: (prt1_2.a = prt2_2.b)
+ -> Seq Scan on prt1_p2 prt1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p2 prt2_2
+ Filter: (a = 0)
+ -> Hash
+ -> Seq Scan on prt1_e_p2 prt1_e_2
+ Filter: (c = 0)
+ -> Hash Full Join
+ Hash Cond: (prt1_3.a = ((prt1_e_3.a + prt1_e_3.b) / 2))
+ Filter: ((prt1_3.a = (50)) OR (prt2_3.b = (75)) OR (((prt1_e_3.a + prt1_e_3.b) / 2) = (50)))
+ -> Hash Full Join
+ Hash Cond: (prt1_3.a = prt2_3.b)
+ -> Seq Scan on prt1_p3 prt1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_p3 prt2_3
+ Filter: (a = 0)
+ -> Hash
+ -> Seq Scan on prt1_e_p3 prt1_e_3
+ Filter: (c = 0)
+(42 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
+----+-----+----+-----+----------+-----
+ 50 | 50 | | | 100 | 50
+ | | 75 | 75 | |
+(2 rows)
+
+-- Semi-join
+EXPLAIN (COSTS OFF)
+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;
+ QUERY PLAN
+---------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop
+ Join Filter: (t1_2.a = t1_5.b)
+ -> HashAggregate
+ Group Key: t1_5.b
+ -> Hash Join
+ Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_5.b)
+ -> Seq Scan on prt1_e_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt2_p1 t1_5
+ Filter: (a = 0)
+ -> Index Scan using iprt1_p1_a on prt1_p1 t1_2
+ Index Cond: (a = ((t2_1.a + t2_1.b) / 2))
+ Filter: (b = 0)
+ -> Nested Loop
+ Join Filter: (t1_3.a = t1_6.b)
+ -> HashAggregate
+ Group Key: t1_6.b
+ -> Hash Join
+ Hash Cond: (((t2_2.a + t2_2.b) / 2) = t1_6.b)
+ -> Seq Scan on prt1_e_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt2_p2 t1_6
+ Filter: (a = 0)
+ -> Index Scan using iprt1_p2_a on prt1_p2 t1_3
+ Index Cond: (a = ((t2_2.a + t2_2.b) / 2))
+ Filter: (b = 0)
+ -> Nested Loop
+ Join Filter: (t1_4.a = t1_7.b)
+ -> HashAggregate
+ Group Key: t1_7.b
+ -> Nested Loop
+ -> Seq Scan on prt2_p3 t1_7
+ Filter: (a = 0)
+ -> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_3
+ Index Cond: (((a + b) / 2) = t1_7.b)
+ -> Index Scan using iprt1_p3_a on prt1_p3 t1_4
+ Index Cond: (a = ((t2_3.a + t2_3.b) / 2))
+ Filter: (b = 0)
+(41 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)
+
+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
+---------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop
+ -> HashAggregate
+ Group Key: t1_6.b
+ -> Hash Semi Join
+ Hash Cond: (t1_6.b = ((t1_9.a + t1_9.b) / 2))
+ -> Seq Scan on prt2_p1 t1_6
+ -> Hash
+ -> Seq Scan on prt1_e_p1 t1_9
+ Filter: (c = 0)
+ -> Index Scan using iprt1_p1_a on prt1_p1 t1_3
+ Index Cond: (a = t1_6.b)
+ Filter: (b = 0)
+ -> Nested Loop
+ -> HashAggregate
+ Group Key: t1_7.b
+ -> Hash Semi Join
+ Hash Cond: (t1_7.b = ((t1_10.a + t1_10.b) / 2))
+ -> Seq Scan on prt2_p2 t1_7
+ -> Hash
+ -> Seq Scan on prt1_e_p2 t1_10
+ Filter: (c = 0)
+ -> Index Scan using iprt1_p2_a on prt1_p2 t1_4
+ Index Cond: (a = t1_7.b)
+ Filter: (b = 0)
+ -> Nested Loop
+ -> HashAggregate
+ Group Key: t1_8.b
+ -> Hash Semi Join
+ Hash Cond: (t1_8.b = ((t1_11.a + t1_11.b) / 2))
+ -> Seq Scan on prt2_p3 t1_8
+ -> Hash
+ -> Seq Scan on prt1_e_p3 t1_11
+ Filter: (c = 0)
+ -> Index Scan using iprt1_p3_a on prt1_p3 t1_5
+ Index Cond: (a = t1_8.b)
+ Filter: (b = 0)
+(39 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)
+
+-- 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
+------------------------------------------------------------------
+ Merge Append
+ Sort Key: t1.a
+ -> Merge Semi Join
+ Merge Cond: (t1_3.a = t1_6.b)
+ -> Sort
+ Sort Key: t1_3.a
+ -> Seq Scan on prt1_p1 t1_3
+ Filter: (b = 0)
+ -> Merge Semi Join
+ Merge Cond: (t1_6.b = (((t1_9.a + t1_9.b) / 2)))
+ -> Sort
+ Sort Key: t1_6.b
+ -> Seq Scan on prt2_p1 t1_6
+ -> Sort
+ Sort Key: (((t1_9.a + t1_9.b) / 2))
+ -> Seq Scan on prt1_e_p1 t1_9
+ Filter: (c = 0)
+ -> Merge Semi Join
+ Merge Cond: (t1_4.a = t1_7.b)
+ -> Sort
+ Sort Key: t1_4.a
+ -> Seq Scan on prt1_p2 t1_4
+ Filter: (b = 0)
+ -> Merge Semi Join
+ Merge Cond: (t1_7.b = (((t1_10.a + t1_10.b) / 2)))
+ -> Sort
+ Sort Key: t1_7.b
+ -> Seq Scan on prt2_p2 t1_7
+ -> Sort
+ Sort Key: (((t1_10.a + t1_10.b) / 2))
+ -> Seq Scan on prt1_e_p2 t1_10
+ Filter: (c = 0)
+ -> Merge Semi Join
+ Merge Cond: (t1_5.a = t1_8.b)
+ -> Sort
+ Sort Key: t1_5.a
+ -> Seq Scan on prt1_p3 t1_5
+ Filter: (b = 0)
+ -> Merge Semi Join
+ Merge Cond: (t1_8.b = (((t1_11.a + t1_11.b) / 2)))
+ -> Sort
+ Sort Key: t1_8.b
+ -> Seq Scan on prt2_p3 t1_8
+ -> Sort
+ Sort Key: (((t1_11.a + t1_11.b) / 2))
+ -> Seq Scan on prt1_e_p3 t1_11
+ Filter: (c = 0)
+(47 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)
+
+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
+----------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b, ((t3.a + t3.b))
+ -> Append
+ -> Merge Left Join
+ Merge Cond: (t1_1.a = t2_1.b)
+ -> Sort
+ Sort Key: t1_1.a
+ -> Merge Left Join
+ 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_p1 t3_1
+ Filter: (c = 0)
+ -> Sort
+ Sort Key: t1_1.a
+ -> Seq Scan on prt1_p1 t1_1
+ -> Sort
+ Sort Key: t2_1.b
+ -> Seq Scan on prt2_p1 t2_1
+ -> Merge Left Join
+ Merge Cond: (t1_2.a = t2_2.b)
+ -> Sort
+ Sort Key: t1_2.a
+ -> Merge Left Join
+ 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_p2 t3_2
+ Filter: (c = 0)
+ -> Sort
+ Sort Key: t1_2.a
+ -> Seq Scan on prt1_p2 t1_2
+ -> Sort
+ Sort Key: t2_2.b
+ -> 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
+(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) 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)
+
+-- MergeAppend on nullable column
+-- This should generate a partitionwise join, but currently fails to
+EXPLAIN (COSTS OFF)
+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;
+ QUERY PLAN
+-----------------------------------------------------------
+ Sort
+ Sort Key: prt1.a, prt2.b
+ -> Merge Left Join
+ Merge Cond: (prt1.a = prt2.b)
+ -> Sort
+ Sort Key: prt1.a
+ -> Append
+ -> Seq Scan on prt1_p1 prt1_1
+ Filter: ((a < 450) AND (b = 0))
+ -> Seq Scan on prt1_p2 prt1_2
+ Filter: ((a < 450) AND (b = 0))
+ -> Sort
+ Sort Key: prt2.b
+ -> Append
+ -> Seq Scan on prt2_p2 prt2_1
+ Filter: (b > 250)
+ -> Seq Scan on prt2_p3 prt2_2
+ Filter: (b > 250)
+(18 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)
+
+-- merge join when expression with whole-row reference needs to be sorted;
+-- partitionwise join does not apply
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.b FROM prt1 t1, prt2 t2 WHERE t1::text = t2::text AND t1.a = t2.b ORDER BY t1.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Merge Join
+ Merge Cond: ((t1.a = t2.b) AND (((((t1.*)::prt1))::text) = ((((t2.*)::prt2))::text)))
+ -> Sort
+ Sort Key: t1.a, ((((t1.*)::prt1))::text)
+ -> Result
+ -> Append
+ -> Seq Scan on prt1_p1 t1_1
+ -> Seq Scan on prt1_p2 t1_2
+ -> Seq Scan on prt1_p3 t1_3
+ -> Sort
+ Sort Key: t2.b, ((((t2.*)::prt2))::text)
+ -> Result
+ -> Append
+ -> Seq Scan on prt2_p1 t2_1
+ -> Seq Scan on prt2_p2 t2_2
+ -> Seq Scan on prt2_p3 t2_3
+(16 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)
+
+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;
+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.a, prt2_m.b
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((prt1_m_1.a = ((prt2_m_1.b + prt2_m_1.a) / 2)) AND (((prt1_m_1.a + prt1_m_1.b) / 2) = prt2_m_1.b))
+ -> Seq Scan on prt1_m_p1 prt1_m_1
+ Filter: (c = 0)
+ -> Hash
+ -> Seq Scan on prt2_m_p1 prt2_m_1
+ Filter: (c = 0)
+ -> Hash Full Join
+ Hash Cond: ((prt1_m_2.a = ((prt2_m_2.b + prt2_m_2.a) / 2)) AND (((prt1_m_2.a + prt1_m_2.b) / 2) = prt2_m_2.b))
+ -> Seq Scan on prt1_m_p2 prt1_m_2
+ Filter: (c = 0)
+ -> Hash
+ -> Seq Scan on prt2_m_p2 prt2_m_2
+ Filter: (c = 0)
+ -> Hash Full Join
+ Hash Cond: ((prt1_m_3.a = ((prt2_m_3.b + prt2_m_3.a) / 2)) AND (((prt1_m_3.a + prt1_m_3.b) / 2) = prt2_m_3.b))
+ -> Seq Scan on prt1_m_p3 prt1_m_3
+ Filter: (c = 0)
+ -> Hash
+ -> Seq Scan on prt2_m_p3 prt2_m_3
+ 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.
+--
+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
+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_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_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 = 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_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 = ltrim(t3_3.c, 'A'::text))
+ -> Hash Join
+ Hash Cond: ((t1_3.b = t2_3.b) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_p3 t1_3
+ -> Hash
+ -> Seq Scan on plt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_e_p3 t3_3
+(32 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)
+
+-- 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;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a;
+ QUERY PLAN
+--------------------------------------------------
+ Hash Left Join
+ Hash Cond: (t2.b = a)
+ -> Append
+ -> 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
+ -> Hash Join
+ Hash Cond: (t3_2.a = t2_2.b)
+ -> Seq Scan on prt1_p2 t3_2
+ -> Hash
+ -> Seq Scan on prt2_p2 t2_2
+ -> Hash Join
+ Hash Cond: (t3_3.a = t2_3.b)
+ -> Seq Scan on prt1_p3 t3_3
+ -> Hash
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Result
+ One-Time Filter: false
+(21 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+--------------------------------------------
+ Sort
+ Sort Key: a, t2.b
+ -> Hash Left Join
+ Hash Cond: (t2.b = a)
+ -> Append
+ -> 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)
+ -> Hash
+ -> Result
+ One-Time Filter: false
+(14 rows)
+
+--
+-- tests for hash partitioned tables.
+--
+CREATE TABLE pht1 (a int, b int, c text) PARTITION BY HASH(c);
+CREATE TABLE pht1_p1 PARTITION OF pht1 FOR VALUES WITH (MODULUS 3, REMAINDER 0);
+CREATE TABLE pht1_p2 PARTITION OF pht1 FOR VALUES WITH (MODULUS 3, REMAINDER 1);
+CREATE TABLE pht1_p3 PARTITION OF pht1 FOR VALUES WITH (MODULUS 3, REMAINDER 2);
+INSERT INTO pht1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE pht1;
+CREATE TABLE pht2 (a int, b int, c text) PARTITION BY HASH(c);
+CREATE TABLE pht2_p1 PARTITION OF pht2 FOR VALUES WITH (MODULUS 3, REMAINDER 0);
+CREATE TABLE pht2_p2 PARTITION OF pht2 FOR VALUES WITH (MODULUS 3, REMAINDER 1);
+CREATE TABLE pht2_p3 PARTITION OF pht2 FOR VALUES WITH (MODULUS 3, REMAINDER 2);
+INSERT INTO pht2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE pht2;
+--
+-- hash partitioned by expression
+--
+CREATE TABLE pht1_e (a int, b int, c text) PARTITION BY HASH(ltrim(c, 'A'));
+CREATE TABLE pht1_e_p1 PARTITION OF pht1_e FOR VALUES WITH (MODULUS 3, REMAINDER 0);
+CREATE TABLE pht1_e_p2 PARTITION OF pht1_e FOR VALUES WITH (MODULUS 3, REMAINDER 1);
+CREATE TABLE pht1_e_p3 PARTITION OF pht1_e FOR VALUES WITH (MODULUS 3, REMAINDER 2);
+INSERT INTO pht1_e SELECT i, i, 'A' || to_char(i/50, 'FM0000') FROM generate_series(0, 299, 2) i;
+ANALYZE pht1_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 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;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ GroupAggregate
+ Group Key: t1.c, t2.c, t3.c
+ -> Sort
+ Sort Key: t1.c, t3.c
+ -> Append
+ -> 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 pht1_p1 t1_1
+ -> Hash
+ -> Seq Scan on pht2_p1 t2_1
+ -> Hash
+ -> Seq Scan on pht1_e_p1 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 pht1_p2 t1_2
+ -> Hash
+ -> Seq Scan on pht2_p2 t2_2
+ -> Hash
+ -> Seq Scan on pht1_e_p2 t3_2
+ -> Hash Join
+ Hash Cond: (t1_3.c = ltrim(t3_3.c, 'A'::text))
+ -> Hash Join
+ Hash Cond: ((t1_3.b = t2_3.b) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on pht1_p3 t1_3
+ -> Hash
+ -> Seq Scan on pht2_p3 t2_3
+ -> Hash
+ -> Seq Scan on pht1_e_p3 t3_3
+(32 rows)
+
+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;
+ 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
+(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_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)
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_p3 t1_3
+ Filter: (b = 0)
+(21 rows)
+
+-- test default partition behavior for list
+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;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.c
+ -> HashAggregate
+ Group Key: t1.c, t2.c
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.c = t1_1.c)
+ -> Seq Scan on plt2_p1 t2_1
+ -> Hash
+ -> 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_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_p2 t1_2
+ Filter: ((a % 25) = 0)
+ -> Hash Join
+ Hash Cond: (t2_3.c = t1_3.c)
+ -> Seq Scan on plt2_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_p3 t1_3
+ Filter: ((a % 25) = 0)
+(23 rows)
+
+--
+-- multiple levels of partitioning
+--
+CREATE TABLE prt1_l (a int, b int, c varchar) PARTITION BY RANGE(a);
+CREATE TABLE prt1_l_p1 PARTITION OF prt1_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt1_l_p2 PARTITION OF prt1_l FOR VALUES FROM (250) TO (500) PARTITION BY LIST (c);
+CREATE TABLE prt1_l_p2_p1 PARTITION OF prt1_l_p2 FOR VALUES IN ('0000', '0001');
+CREATE TABLE prt1_l_p2_p2 PARTITION OF prt1_l_p2 FOR VALUES IN ('0002', '0003');
+CREATE TABLE prt1_l_p3 PARTITION OF prt1_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (b);
+CREATE TABLE prt1_l_p3_p1 PARTITION OF prt1_l_p3 FOR VALUES FROM (0) TO (13);
+CREATE TABLE prt1_l_p3_p2 PARTITION OF prt1_l_p3 FOR VALUES FROM (13) TO (25);
+INSERT INTO prt1_l SELECT i, i % 25, to_char(i % 4, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt1_l;
+CREATE TABLE prt2_l (a int, b int, c varchar) PARTITION BY RANGE(b);
+CREATE TABLE prt2_l_p1 PARTITION OF prt2_l FOR VALUES FROM (0) TO (250);
+CREATE TABLE prt2_l_p2 PARTITION OF prt2_l FOR VALUES FROM (250) TO (500) PARTITION BY LIST (c);
+CREATE TABLE prt2_l_p2_p1 PARTITION OF prt2_l_p2 FOR VALUES IN ('0000', '0001');
+CREATE TABLE prt2_l_p2_p2 PARTITION OF prt2_l_p2 FOR VALUES IN ('0002', '0003');
+CREATE TABLE prt2_l_p3 PARTITION OF prt2_l FOR VALUES FROM (500) TO (600) PARTITION BY RANGE (a);
+CREATE TABLE prt2_l_p3_p1 PARTITION OF prt2_l_p3 FOR VALUES FROM (0) TO (13);
+CREATE TABLE prt2_l_p3_p2 PARTITION OF prt2_l_p3 FOR VALUES FROM (13) TO (25);
+INSERT INTO prt2_l SELECT i % 25, i, to_char(i % 4, 'FM0000') FROM generate_series(0, 599, 3) i;
+ANALYZE prt2_l;
+-- inner join, qual covering only top-level partitions
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+-------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_l_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_l_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Append
+ -> Seq Scan on prt2_l_p2_p1 t2_3
+ -> Seq Scan on prt2_l_p2_p2 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_l_p2_p1 t1_3
+ Filter: (b = 0)
+ -> Seq Scan on prt1_l_p2_p2 t1_4
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_6.b = t1_5.a)
+ -> Append
+ -> Seq Scan on prt2_l_p3_p1 t2_6
+ -> Seq Scan on prt2_l_p3_p2 t2_7
+ -> Hash
+ -> Seq Scan on prt1_l_p3_p1 t1_5
+ Filter: (b = 0)
+(28 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l 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 | 0002 | 150 | 0002
+ 300 | 0000 | 300 | 0000
+ 450 | 0002 | 450 | 0002
+(4 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t2_1.b = t1_1.a) AND ((t2_1.c)::text = (t1_1.c)::text))
+ -> Seq Scan on prt2_l_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_l_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: ((t2_2.b = t1_2.a) AND ((t2_2.c)::text = (t1_2.c)::text))
+ -> Seq Scan on prt2_l_p2_p1 t2_2
+ -> Hash
+ -> Seq Scan on prt1_l_p2_p1 t1_2
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: ((t2_3.b = t1_3.a) AND ((t2_3.c)::text = (t1_3.c)::text))
+ -> Seq Scan on prt2_l_p2_p2 t2_3
+ -> Hash
+ -> Seq Scan on prt1_l_p2_p2 t1_3
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: ((t2_5.b = t1_4.a) AND ((t2_5.c)::text = (t1_4.c)::text))
+ -> Append
+ -> Seq Scan on prt2_l_p3_p1 t2_5
+ -> Seq Scan on prt2_l_p3_p2 t2_6
+ -> Hash
+ -> Seq Scan on prt1_l_p3_p1 t1_4
+ Filter: (b = 0)
+(29 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 0 | 0000 | 0 | 0000
+ 50 | 0002 | |
+ 100 | 0000 | |
+ 150 | 0002 | 150 | 0002
+ 200 | 0000 | |
+ 250 | 0002 | |
+ 300 | 0000 | 300 | 0000
+ 350 | 0002 | |
+ 400 | 0000 | |
+ 450 | 0002 | 450 | 0002
+ 500 | 0000 | |
+ 550 | 0002 | |
+(12 rows)
+
+-- right join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t1_1.a = t2_1.b) AND ((t1_1.c)::text = (t2_1.c)::text))
+ -> Seq Scan on prt1_l_p1 t1_1
+ -> Hash
+ -> Seq Scan on prt2_l_p1 t2_1
+ Filter: (a = 0)
+ -> Hash Right Join
+ Hash Cond: ((t1_2.a = t2_2.b) AND ((t1_2.c)::text = (t2_2.c)::text))
+ -> Seq Scan on prt1_l_p2_p1 t1_2
+ -> Hash
+ -> Seq Scan on prt2_l_p2_p1 t2_2
+ Filter: (a = 0)
+ -> Hash Right Join
+ Hash Cond: ((t1_3.a = t2_3.b) AND ((t1_3.c)::text = (t2_3.c)::text))
+ -> Seq Scan on prt1_l_p2_p2 t1_3
+ -> Hash
+ -> Seq Scan on prt2_l_p2_p2 t2_3
+ Filter: (a = 0)
+ -> Hash Right Join
+ Hash Cond: ((t1_5.a = t2_4.b) AND ((t1_5.c)::text = (t2_4.c)::text))
+ -> Append
+ -> Seq Scan on prt1_l_p3_p1 t1_5
+ -> Seq Scan on prt1_l_p3_p2 t1_6
+ -> Hash
+ -> Seq Scan on prt2_l_p3_p1 t2_4
+ Filter: (a = 0)
+(29 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 0 | 0000 | 0 | 0000
+ 150 | 0002 | 150 | 0002
+ 300 | 0000 | 300 | 0000
+ 450 | 0002 | 450 | 0002
+ | | 75 | 0003
+ | | 225 | 0001
+ | | 375 | 0003
+ | | 525 | 0001
+(8 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.a = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: prt1_l.a, prt2_l.b
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((prt1_l_1.a = prt2_l_1.b) AND ((prt1_l_1.c)::text = (prt2_l_1.c)::text))
+ -> Seq Scan on prt1_l_p1 prt1_l_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_l_p1 prt2_l_1
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: ((prt1_l_2.a = prt2_l_2.b) AND ((prt1_l_2.c)::text = (prt2_l_2.c)::text))
+ -> Seq Scan on prt1_l_p2_p1 prt1_l_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_l_p2_p1 prt2_l_2
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: ((prt1_l_3.a = prt2_l_3.b) AND ((prt1_l_3.c)::text = (prt2_l_3.c)::text))
+ -> Seq Scan on prt1_l_p2_p2 prt1_l_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_l_p2_p2 prt2_l_3
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: ((prt1_l_4.a = prt2_l_4.b) AND ((prt1_l_4.c)::text = (prt2_l_4.c)::text))
+ -> Seq Scan on prt1_l_p3_p1 prt1_l_4
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_l_p3_p1 prt2_l_4
+ Filter: (a = 0)
+(31 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.a = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 0 | 0000 | 0 | 0000
+ 50 | 0002 | |
+ 100 | 0000 | |
+ 150 | 0002 | 150 | 0002
+ 200 | 0000 | |
+ 250 | 0002 | |
+ 300 | 0000 | 300 | 0000
+ 350 | 0002 | |
+ 400 | 0000 | |
+ 450 | 0002 | 450 | 0002
+ 500 | 0000 | |
+ 550 | 0002 | |
+ | | 75 | 0003
+ | | 225 | 0001
+ | | 375 | 0003
+ | | 525 | 0001
+(16 rows)
+
+-- lateral partitionwise join
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+ (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+ ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Left Join
+ -> Seq Scan on prt1_l_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: ((t3_1.b = t2_1.a) AND ((t3_1.c)::text = (t2_1.c)::text))
+ -> Seq Scan on prt2_l_p1 t3_1
+ -> Hash
+ -> Seq Scan on prt1_l_p1 t2_1
+ Filter: ((t1_1.a = a) AND ((t1_1.c)::text = (c)::text))
+ -> Nested Loop Left Join
+ -> Seq Scan on prt1_l_p2_p1 t1_2
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: ((t3_2.b = t2_2.a) AND ((t3_2.c)::text = (t2_2.c)::text))
+ -> Seq Scan on prt2_l_p2_p1 t3_2
+ -> Hash
+ -> Seq Scan on prt1_l_p2_p1 t2_2
+ Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text))
+ -> Nested Loop Left Join
+ -> Seq Scan on prt1_l_p2_p2 t1_3
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
+ -> Seq Scan on prt2_l_p2_p2 t3_3
+ -> Hash
+ -> Seq Scan on prt1_l_p2_p2 t2_3
+ Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
+ -> Nested Loop Left Join
+ -> Seq Scan on prt1_l_p3_p1 t1_4
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: ((t3_5.b = t2_5.a) AND ((t3_5.c)::text = (t2_5.c)::text))
+ -> Append
+ -> Seq Scan on prt2_l_p3_p1 t3_5
+ -> Seq Scan on prt2_l_p3_p2 t3_6
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_l_p3_p1 t2_5
+ Filter: ((t1_4.a = a) AND ((t1_4.c)::text = (c)::text))
+ -> Seq Scan on prt1_l_p3_p2 t2_6
+ Filter: ((t1_4.a = a) AND ((t1_4.c)::text = (c)::text))
+(44 rows)
+
+SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
+ (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss
+ ON t1.a = ss.t2a AND t1.c = ss.t2c WHERE t1.b = 0 ORDER BY t1.a;
+ a | b | c | t2a | t2c | t2b | t3b | least
+-----+---+------+-----+------+-----+-----+-------
+ 0 | 0 | 0000 | 0 | 0000 | 0 | 0 | 0
+ 50 | 0 | 0002 | | | | |
+ 100 | 0 | 0000 | | | | |
+ 150 | 0 | 0002 | 150 | 0002 | 0 | 150 | 150
+ 200 | 0 | 0000 | | | | |
+ 250 | 0 | 0002 | | | | |
+ 300 | 0 | 0000 | 300 | 0000 | 0 | 300 | 300
+ 350 | 0 | 0002 | | | | |
+ 400 | 0 | 0000 | | | | |
+ 450 | 0 | 0002 | 450 | 0002 | 0 | 450 | 450
+ 500 | 0 | 0000 | | | | |
+ 550 | 0 | 0002 | | | | |
+(12 rows)
+
+-- join with one side empty
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Hash Left Join
+ Hash Cond: ((t2.b = a) AND (t2.a = b) AND ((t2.c)::text = (c)::text))
+ -> Append
+ -> Seq Scan on prt2_l_p1 t2_1
+ -> Seq Scan on prt2_l_p2_p1 t2_2
+ -> Seq Scan on prt2_l_p2_p2 t2_3
+ -> Seq Scan on prt2_l_p3_p1 t2_4
+ -> Seq Scan on prt2_l_p3_p2 t2_5
+ -> Hash
+ -> Result
+ One-Time Filter: false
+(11 rows)
+
+-- Test case to verify proper handling of subqueries in a partitioned delete.
+-- The weird-looking lateral join is just there to force creation of a
+-- nestloop parameter within the subquery, which exposes the problem if the
+-- planner fails to make multiple copies of the subquery as appropriate.
+EXPLAIN (COSTS OFF)
+DELETE FROM prt1_l
+WHERE EXISTS (
+ SELECT 1
+ FROM int4_tbl,
+ LATERAL (SELECT int4_tbl.f1 FROM int8_tbl LIMIT 2) ss
+ WHERE prt1_l.c IS NULL);
+ QUERY PLAN
+----------------------------------------------------------
+ Delete on prt1_l
+ Delete on prt1_l_p1 prt1_l_1
+ Delete on prt1_l_p3_p1 prt1_l_2
+ Delete on prt1_l_p3_p2 prt1_l_3
+ -> Nested Loop Semi Join
+ -> Append
+ -> Seq Scan on prt1_l_p1 prt1_l_1
+ Filter: (c IS NULL)
+ -> Seq Scan on prt1_l_p3_p1 prt1_l_2
+ Filter: (c IS NULL)
+ -> Seq Scan on prt1_l_p3_p2 prt1_l_3
+ Filter: (c IS NULL)
+ -> Materialize
+ -> Nested Loop
+ -> Seq Scan on int4_tbl
+ -> Subquery Scan on ss
+ -> Limit
+ -> Seq Scan on int8_tbl
+(18 rows)
+
+--
+-- negative testcases
+--
+CREATE TABLE prt1_n (a int, b int, c varchar) PARTITION BY RANGE(c);
+CREATE TABLE prt1_n_p1 PARTITION OF prt1_n FOR VALUES FROM ('0000') TO ('0250');
+CREATE TABLE prt1_n_p2 PARTITION OF prt1_n FOR VALUES FROM ('0250') TO ('0500');
+INSERT INTO prt1_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 499, 2) i;
+ANALYZE prt1_n;
+CREATE TABLE prt2_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt2_n_p1 PARTITION OF prt2_n FOR VALUES IN ('0000', '0003', '0004', '0010', '0006', '0007');
+CREATE TABLE prt2_n_p2 PARTITION OF prt2_n FOR VALUES IN ('0001', '0005', '0002', '0009', '0008', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt2_n;
+CREATE TABLE prt3_n (a int, b int, c text) PARTITION BY LIST(c);
+CREATE TABLE prt3_n_p1 PARTITION OF prt3_n FOR VALUES IN ('0000', '0004', '0006', '0007');
+CREATE TABLE prt3_n_p2 PARTITION OF prt3_n FOR VALUES IN ('0001', '0002', '0008', '0010');
+CREATE TABLE prt3_n_p3 PARTITION OF prt3_n FOR VALUES IN ('0003', '0005', '0009', '0011');
+INSERT INTO prt2_n SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt3_n;
+CREATE TABLE prt4_n (a int, b int, c text) PARTITION BY RANGE(a);
+CREATE TABLE prt4_n_p1 PARTITION OF prt4_n FOR VALUES FROM (0) TO (300);
+CREATE TABLE prt4_n_p2 PARTITION OF prt4_n FOR VALUES FROM (300) TO (500);
+CREATE TABLE prt4_n_p3 PARTITION OF prt4_n FOR VALUES FROM (500) TO (600);
+INSERT INTO prt4_n SELECT i, i, to_char(i, 'FM0000') FROM generate_series(0, 599, 2) i;
+ANALYZE prt4_n;
+-- partitionwise join can not be applied if the partition ranges differ
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt4_n t2 WHERE t1.a = t2.a;
+ QUERY PLAN
+----------------------------------------------
+ Hash Join
+ Hash Cond: (t1.a = t2.a)
+ -> Append
+ -> Seq Scan on prt1_p1 t1_1
+ -> Seq Scan on prt1_p2 t1_2
+ -> Seq Scan on prt1_p3 t1_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt4_n_p1 t2_1
+ -> Seq Scan on prt4_n_p2 t2_2
+ -> Seq Scan on prt4_n_p3 t2_3
+(11 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
+--------------------------------------------------------
+ Hash Join
+ Hash Cond: (t2.a = t1.a)
+ -> Append
+ -> Seq Scan on prt4_n_p1 t2_1
+ -> Seq Scan on prt4_n_p2 t2_2
+ -> Seq Scan on prt4_n_p3 t2_3
+ -> Hash
+ -> Append
+ -> Hash Join
+ Hash Cond: (t1_1.a = t3_1.b)
+ -> Seq Scan on prt1_p1 t1_1
+ -> Hash
+ -> Seq Scan on prt2_p1 t3_1
+ -> Hash Join
+ Hash Cond: (t1_2.a = t3_2.b)
+ -> Seq Scan on prt1_p2 t1_2
+ -> Hash
+ -> Seq Scan on prt2_p2 t3_2
+ -> Hash Join
+ Hash Cond: (t1_3.a = t3_3.b)
+ -> Seq Scan on prt1_p3 t1_3
+ -> Hash
+ -> Seq Scan on prt2_p3 t3_3
+(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
+---------------------------------------------------------
+ Nested Loop Left Join
+ -> Append
+ -> Seq Scan on prt1_p1 t1_1
+ -> Seq Scan on prt1_p2 t1_2
+ -> Seq Scan on prt1_p3 t1_3
+ -> Append
+ -> Index Scan using iprt2_p1_b on prt2_p1 t2_1
+ Index Cond: (b > t1.a)
+ -> Index Scan using iprt2_p2_b on prt2_p2 t2_2
+ Index Cond: (b > t1.a)
+ -> Index Scan using iprt2_p3_b on prt2_p3 t2_3
+ Index Cond: (b > t1.a)
+(12 rows)
+
+-- equi-join with join condition on partial keys does not qualify for
+-- partitionwise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1, prt2_m t2 WHERE t1.a = (t2.b + t2.a)/2;
+ QUERY PLAN
+----------------------------------------------
+ Hash Join
+ Hash Cond: (((t2.b + t2.a) / 2) = t1.a)
+ -> Append
+ -> Seq Scan on prt2_m_p1 t2_1
+ -> Seq Scan on prt2_m_p2 t2_2
+ -> Seq Scan on prt2_m_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_m_p1 t1_1
+ -> Seq Scan on prt1_m_p2 t1_2
+ -> Seq Scan on prt1_m_p3 t1_3
+(11 rows)
+
+-- equi-join between out-of-order partition key columns does not qualify for
+-- partitionwise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.a = t2.b;
+ QUERY PLAN
+----------------------------------------------
+ Hash Left Join
+ Hash Cond: (t1.a = t2.b)
+ -> Append
+ -> Seq Scan on prt1_m_p1 t1_1
+ -> Seq Scan on prt1_m_p2 t1_2
+ -> Seq Scan on prt1_m_p3 t1_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_m_p1 t2_1
+ -> Seq Scan on prt2_m_p2 t2_2
+ -> Seq Scan on prt2_m_p3 t2_3
+(11 rows)
+
+-- equi-join between non-key columns does not qualify for partitionwise join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_m t1 LEFT JOIN prt2_m t2 ON t1.c = t2.c;
+ QUERY PLAN
+----------------------------------------------
+ Hash Left Join
+ Hash Cond: (t1.c = t2.c)
+ -> Append
+ -> Seq Scan on prt1_m_p1 t1_1
+ -> Seq Scan on prt1_m_p2 t1_2
+ -> Seq Scan on prt1_m_p3 t1_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_m_p1 t2_1
+ -> Seq Scan on prt2_m_p2 t2_2
+ -> Seq Scan on prt2_m_p3 t2_3
+(11 rows)
+
+-- partitionwise join can not be applied for a join between list and range
+-- partitioned tables
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 LEFT JOIN prt2_n t2 ON (t1.c = t2.c);
+ QUERY PLAN
+----------------------------------------------
+ Hash Right Join
+ Hash Cond: (t2.c = (t1.c)::text)
+ -> Append
+ -> Seq Scan on prt2_n_p1 t2_1
+ -> Seq Scan on prt2_n_p2 t2_2
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_n_p1 t1_1
+ -> Seq Scan on prt1_n_p2 t1_2
+(9 rows)
+
+-- partitionwise join can not be applied between tables with different
+-- partition lists
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 JOIN prt2_n t2 ON (t1.c = t2.c) JOIN plt1 t3 ON (t1.c = t3.c);
+ QUERY PLAN
+----------------------------------------------------------
+ Hash Join
+ Hash Cond: (t2.c = (t1.c)::text)
+ -> Append
+ -> Seq Scan on prt2_n_p1 t2_1
+ -> Seq Scan on prt2_n_p2 t2_2
+ -> Hash
+ -> Hash Join
+ Hash Cond: (t3.c = (t1.c)::text)
+ -> Append
+ -> 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_1
+ -> Seq Scan on prt1_n_p2 t1_2
+(16 rows)
+
+-- partitionwise join can not be applied for a join between key column and
+-- non-key column
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_n t1 FULL JOIN prt1 t2 ON (t1.c = t2.c);
+ QUERY PLAN
+----------------------------------------------
+ Hash Full Join
+ Hash Cond: ((t2.c)::text = (t1.c)::text)
+ -> Append
+ -> Seq Scan on prt1_p1 t2_1
+ -> Seq Scan on prt1_p2 t2_2
+ -> Seq Scan on prt1_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_n_p1 t1_1
+ -> Seq Scan on prt1_n_p2 t1_2
+(10 rows)
+
+--
+-- Test some other plan types in a partitionwise join (unfortunately,
+-- we need larger tables to get the planner to choose these plan types)
+--
+create temp table prtx1 (a integer, b integer, c integer)
+ partition by range (a);
+create temp table prtx1_1 partition of prtx1 for values from (1) to (11);
+create temp table prtx1_2 partition of prtx1 for values from (11) to (21);
+create temp table prtx1_3 partition of prtx1 for values from (21) to (31);
+create temp table prtx2 (a integer, b integer, c integer)
+ partition by range (a);
+create temp table prtx2_1 partition of prtx2 for values from (1) to (11);
+create temp table prtx2_2 partition of prtx2 for values from (11) to (21);
+create temp table prtx2_3 partition of prtx2 for values from (21) to (31);
+insert into prtx1 select 1 + i%30, i, i
+ from generate_series(1,1000) i;
+insert into prtx2 select 1 + i%30, i, i
+ from generate_series(1,500) i, generate_series(1,10) j;
+create index on prtx2 (b);
+create index on prtx2 (c);
+analyze prtx1;
+analyze prtx2;
+explain (costs off)
+select * from prtx1
+where not exists (select 1 from prtx2
+ where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
+ and a<20 and c=120;
+ QUERY PLAN
+-------------------------------------------------------------
+ Append
+ -> Nested Loop Anti Join
+ -> Seq Scan on prtx1_1
+ Filter: ((a < 20) AND (c = 120))
+ -> Bitmap Heap Scan on prtx2_1
+ Recheck Cond: ((b = prtx1_1.b) AND (c = 123))
+ Filter: (a = prtx1_1.a)
+ -> BitmapAnd
+ -> Bitmap Index Scan on prtx2_1_b_idx
+ Index Cond: (b = prtx1_1.b)
+ -> Bitmap Index Scan on prtx2_1_c_idx
+ Index Cond: (c = 123)
+ -> Nested Loop Anti Join
+ -> Seq Scan on prtx1_2
+ Filter: ((a < 20) AND (c = 120))
+ -> Bitmap Heap Scan on prtx2_2
+ Recheck Cond: ((b = prtx1_2.b) AND (c = 123))
+ Filter: (a = prtx1_2.a)
+ -> BitmapAnd
+ -> Bitmap Index Scan on prtx2_2_b_idx
+ Index Cond: (b = prtx1_2.b)
+ -> Bitmap Index Scan on prtx2_2_c_idx
+ Index Cond: (c = 123)
+(23 rows)
+
+select * from prtx1
+where not exists (select 1 from prtx2
+ where prtx2.a=prtx1.a and prtx2.b=prtx1.b and prtx2.c=123)
+ and a<20 and c=120;
+ a | b | c
+---+-----+-----
+ 1 | 120 | 120
+(1 row)
+
+explain (costs off)
+select * from prtx1
+where not exists (select 1 from prtx2
+ where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
+ and a<20 and c=91;
+ QUERY PLAN
+-----------------------------------------------------------------
+ Append
+ -> Nested Loop Anti Join
+ -> Seq Scan on prtx1_1
+ Filter: ((a < 20) AND (c = 91))
+ -> Bitmap Heap Scan on prtx2_1
+ Recheck Cond: ((b = (prtx1_1.b + 1)) OR (c = 99))
+ Filter: (a = prtx1_1.a)
+ -> BitmapOr
+ -> Bitmap Index Scan on prtx2_1_b_idx
+ Index Cond: (b = (prtx1_1.b + 1))
+ -> Bitmap Index Scan on prtx2_1_c_idx
+ Index Cond: (c = 99)
+ -> Nested Loop Anti Join
+ -> Seq Scan on prtx1_2
+ Filter: ((a < 20) AND (c = 91))
+ -> Bitmap Heap Scan on prtx2_2
+ Recheck Cond: ((b = (prtx1_2.b + 1)) OR (c = 99))
+ Filter: (a = prtx1_2.a)
+ -> BitmapOr
+ -> Bitmap Index Scan on prtx2_2_b_idx
+ Index Cond: (b = (prtx1_2.b + 1))
+ -> Bitmap Index Scan on prtx2_2_c_idx
+ Index Cond: (c = 99)
+(23 rows)
+
+select * from prtx1
+where not exists (select 1 from prtx2
+ where prtx2.a=prtx1.a and (prtx2.b=prtx1.b+1 or prtx2.c=99))
+ and a<20 and c=91;
+ a | b | c
+---+----+----
+ 2 | 91 | 91
+(1 row)
+
+--
+-- Test advanced partition-matching algorithm for partitioned join
+--
+-- Tests for range-partitioned tables
+CREATE TABLE prt1_adv (a int, b int, c varchar) PARTITION BY RANGE (a);
+CREATE TABLE prt1_adv_p1 PARTITION OF prt1_adv FOR VALUES FROM (100) TO (200);
+CREATE TABLE prt1_adv_p2 PARTITION OF prt1_adv FOR VALUES FROM (200) TO (300);
+CREATE TABLE prt1_adv_p3 PARTITION OF prt1_adv FOR VALUES FROM (300) TO (400);
+CREATE INDEX prt1_adv_a_idx ON prt1_adv (a);
+INSERT INTO prt1_adv SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(100, 399) i;
+ANALYZE prt1_adv;
+CREATE TABLE prt2_adv (a int, b int, c varchar) PARTITION BY RANGE (b);
+CREATE TABLE prt2_adv_p1 PARTITION OF prt2_adv FOR VALUES FROM (100) TO (150);
+CREATE TABLE prt2_adv_p2 PARTITION OF prt2_adv FOR VALUES FROM (200) TO (300);
+CREATE TABLE prt2_adv_p3 PARTITION OF prt2_adv FOR VALUES FROM (350) TO (500);
+CREATE INDEX prt2_adv_b_idx ON prt2_adv (b);
+INSERT INTO prt2_adv_p1 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(100, 149) i;
+INSERT INTO prt2_adv_p2 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(200, 299) i;
+INSERT INTO prt2_adv_p3 SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(350, 499) i;
+ANALYZE prt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+ 350 | 0350 | 350 | 0350
+ 375 | 0375 | 375 | 0375
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Semi Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash Semi Join
+ Hash Cond: (t1_2.a = t2_2.b)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash Semi Join
+ Hash Cond: (t1_3.a = t2_3.b)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p3 t2_3
+(21 rows)
+
+SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ a | b | c
+-----+---+------
+ 100 | 0 | 0100
+ 125 | 0 | 0125
+ 200 | 0 | 0200
+ 225 | 0 | 0225
+ 250 | 0 | 0250
+ 275 | 0 | 0275
+ 350 | 0 | 0350
+ 375 | 0 | 0375
+(8 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 150 | 0150 | |
+ 175 | 0175 | |
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+ 300 | 0300 | |
+ 325 | 0325 | |
+ 350 | 0350 | 350 | 0350
+ 375 | 0375 | 375 | 0375
+(12 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Anti Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash Anti Join
+ Hash Cond: (t1_2.a = t2_2.b)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash Anti Join
+ Hash Cond: (t1_3.a = t2_3.b)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p3 t2_3
+(21 rows)
+
+SELECT t1.* FROM prt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ a | b | c
+-----+---+------
+ 150 | 0 | 0150
+ 175 | 0 | 0175
+ 300 | 0 | 0300
+ 325 | 0 | 0325
+(4 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 175 phv, * FROM prt1_adv WHERE prt1_adv.b = 0) t1 FULL JOIN (SELECT 425 phv, * FROM prt2_adv WHERE prt2_adv.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: prt1_adv.a, prt2_adv.b
+ -> Append
+ -> Hash Full Join
+ Hash Cond: (prt1_adv_1.a = prt2_adv_1.b)
+ Filter: (((175) = prt1_adv_1.a) OR ((425) = prt2_adv_1.b))
+ -> Seq Scan on prt1_adv_p1 prt1_adv_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p1 prt2_adv_1
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: (prt1_adv_2.a = prt2_adv_2.b)
+ Filter: (((175) = prt1_adv_2.a) OR ((425) = prt2_adv_2.b))
+ -> Seq Scan on prt1_adv_p2 prt1_adv_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 prt2_adv_2
+ Filter: (a = 0)
+ -> Hash Full Join
+ Hash Cond: (prt2_adv_3.b = prt1_adv_3.a)
+ Filter: (((175) = prt1_adv_3.a) OR ((425) = prt2_adv_3.b))
+ -> Seq Scan on prt2_adv_p3 prt2_adv_3
+ Filter: (a = 0)
+ -> Hash
+ -> Seq Scan on prt1_adv_p3 prt1_adv_3
+ Filter: (b = 0)
+(27 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 175 phv, * FROM prt1_adv WHERE prt1_adv.b = 0) t1 FULL JOIN (SELECT 425 phv, * FROM prt2_adv WHERE prt2_adv.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
+-----+------+-----+------
+ 175 | 0175 | |
+ | | 425 | 0425
+(2 rows)
+
+-- Test cases where one side has an extra partition
+CREATE TABLE prt2_adv_extra PARTITION OF prt2_adv FOR VALUES FROM (500) TO (MAXVALUE);
+INSERT INTO prt2_adv SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(500, 599) i;
+ANALYZE prt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+ 350 | 0350 | 350 | 0350
+ 375 | 0375 | 375 | 0375
+(8 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Semi Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash Semi Join
+ Hash Cond: (t1_2.a = t2_2.b)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash Semi Join
+ Hash Cond: (t1_3.a = t2_3.b)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p3 t2_3
+(21 rows)
+
+SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ a | b | c
+-----+---+------
+ 100 | 0 | 0100
+ 125 | 0 | 0125
+ 200 | 0 | 0200
+ 225 | 0 | 0225
+ 250 | 0 | 0250
+ 275 | 0 | 0275
+ 350 | 0 | 0350
+ 375 | 0 | 0375
+(8 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_3.b = t1_3.a)
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 150 | 0150 | |
+ 175 | 0175 | |
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+ 300 | 0300 | |
+ 325 | 0325 | |
+ 350 | 0350 | 350 | 0350
+ 375 | 0375 | 375 | 0375
+(12 rows)
+
+-- left join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c, t2.a, t2.c FROM prt2_adv t1 LEFT JOIN prt1_adv t2 ON (t1.b = t2.a) WHERE t1.a = 0 ORDER BY t1.b, t2.a;
+ QUERY PLAN
+---------------------------------------------------------
+ Sort
+ Sort Key: t1.b, t2.a
+ -> Hash Right Join
+ Hash Cond: (t2.a = t1.b)
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t2_1
+ -> Seq Scan on prt1_adv_p2 t2_2
+ -> Seq Scan on prt1_adv_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_adv_p1 t1_1
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p2 t1_2
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p3 t1_3
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_extra t1_4
+ Filter: (a = 0)
+(18 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Anti Join
+ Hash Cond: (t1_1.a = t2_1.b)
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash Anti Join
+ Hash Cond: (t1_2.a = t2_2.b)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash Anti Join
+ Hash Cond: (t1_3.a = t2_3.b)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Seq Scan on prt2_adv_p3 t2_3
+(21 rows)
+
+SELECT t1.* FROM prt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ a | b | c
+-----+---+------
+ 150 | 0 | 0150
+ 175 | 0 | 0175
+ 300 | 0 | 0300
+ 325 | 0 | 0325
+(4 rows)
+
+-- anti join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt2_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt1_adv t2 WHERE t1.b = t2.a) AND t1.a = 0 ORDER BY t1.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.b
+ -> Hash Anti Join
+ Hash Cond: (t1.b = t2.a)
+ -> Append
+ -> Seq Scan on prt2_adv_p1 t1_1
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p2 t1_2
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p3 t1_3
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_extra t1_4
+ Filter: (a = 0)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t2_1
+ -> Seq Scan on prt1_adv_p2 t2_2
+ -> Seq Scan on prt1_adv_p3 t2_3
+(18 rows)
+
+-- full join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 175 phv, * FROM prt1_adv WHERE prt1_adv.b = 0) t1 FULL JOIN (SELECT 425 phv, * FROM prt2_adv WHERE prt2_adv.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: prt1_adv.a, prt2_adv.b
+ -> Hash Full Join
+ Hash Cond: (prt2_adv.b = prt1_adv.a)
+ Filter: (((175) = prt1_adv.a) OR ((425) = prt2_adv.b))
+ -> Append
+ -> Seq Scan on prt2_adv_p1 prt2_adv_1
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p2 prt2_adv_2
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p3 prt2_adv_3
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_extra prt2_adv_4
+ Filter: (a = 0)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p1 prt1_adv_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 prt1_adv_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 prt1_adv_3
+ Filter: (b = 0)
+(22 rows)
+
+-- 3-way join where not every pair of relations can do partitioned join
+EXPLAIN (COSTS OFF)
+SELECT t1.b, t1.c, t2.a, t2.c, t3.a, t3.c FROM prt2_adv t1 LEFT JOIN prt1_adv t2 ON (t1.b = t2.a) INNER JOIN prt1_adv t3 ON (t1.b = t3.a) WHERE t1.a = 0 ORDER BY t1.b, t2.a, t3.a;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.b, t2.a
+ -> Append
+ -> Nested Loop Left Join
+ -> Nested Loop
+ -> Seq Scan on prt2_adv_p1 t1_1
+ Filter: (a = 0)
+ -> Index Scan using prt1_adv_p1_a_idx on prt1_adv_p1 t3_1
+ Index Cond: (a = t1_1.b)
+ -> Index Scan using prt1_adv_p1_a_idx on prt1_adv_p1 t2_1
+ Index Cond: (a = t1_1.b)
+ -> Hash Right Join
+ Hash Cond: (t2_2.a = t1_2.b)
+ -> Seq Scan on prt1_adv_p2 t2_2
+ -> Hash
+ -> Hash Join
+ Hash Cond: (t3_2.a = t1_2.b)
+ -> Seq Scan on prt1_adv_p2 t3_2
+ -> Hash
+ -> Seq Scan on prt2_adv_p2 t1_2
+ Filter: (a = 0)
+ -> Hash Right Join
+ Hash Cond: (t2_3.a = t1_3.b)
+ -> Seq Scan on prt1_adv_p3 t2_3
+ -> Hash
+ -> Hash Join
+ Hash Cond: (t3_3.a = t1_3.b)
+ -> Seq Scan on prt1_adv_p3 t3_3
+ -> Hash
+ -> Seq Scan on prt2_adv_p3 t1_3
+ Filter: (a = 0)
+(31 rows)
+
+SELECT t1.b, t1.c, t2.a, t2.c, t3.a, t3.c FROM prt2_adv t1 LEFT JOIN prt1_adv t2 ON (t1.b = t2.a) INNER JOIN prt1_adv t3 ON (t1.b = t3.a) WHERE t1.a = 0 ORDER BY t1.b, t2.a, t3.a;
+ b | c | a | c | a | c
+-----+------+-----+------+-----+------
+ 100 | 0100 | 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125 | 125 | 0125
+ 200 | 0200 | 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275 | 275 | 0275
+ 350 | 0350 | 350 | 0350 | 350 | 0350
+ 375 | 0375 | 375 | 0375 | 375 | 0375
+(8 rows)
+
+DROP TABLE prt2_adv_extra;
+-- Test cases where a partition on one side matches multiple partitions on
+-- the other side; we currently can't do partitioned join in such cases
+ALTER TABLE prt2_adv DETACH PARTITION prt2_adv_p3;
+-- Split prt2_adv_p3 into two partitions so that prt1_adv_p3 matches both
+CREATE TABLE prt2_adv_p3_1 PARTITION OF prt2_adv FOR VALUES FROM (350) TO (375);
+CREATE TABLE prt2_adv_p3_2 PARTITION OF prt2_adv FOR VALUES FROM (375) TO (500);
+INSERT INTO prt2_adv SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(350, 499) i;
+ANALYZE prt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE 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_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3_1 t2_3
+ -> Seq Scan on prt2_adv_p3_2 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(17 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Semi Join
+ Hash Cond: (t1.a = t2.b)
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3_1 t2_3
+ -> Seq Scan on prt2_adv_p3_2 t2_4
+(17 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b
+ -> Hash Right Join
+ Hash Cond: (t2.b = t1.a)
+ -> Append
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3_1 t2_3
+ -> Seq Scan on prt2_adv_p3_2 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+(17 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM prt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Anti Join
+ Hash Cond: (t1.a = t2.b)
+ -> Append
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_3
+ Filter: (b = 0)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3_1 t2_3
+ -> Seq Scan on prt2_adv_p3_2 t2_4
+(17 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 175 phv, * FROM prt1_adv WHERE prt1_adv.b = 0) t1 FULL JOIN (SELECT 425 phv, * FROM prt2_adv WHERE prt2_adv.a = 0) t2 ON (t1.a = t2.b) WHERE t1.phv = t1.a OR t2.phv = t2.b ORDER BY t1.a, t2.b;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: prt1_adv.a, prt2_adv.b
+ -> Hash Full Join
+ Hash Cond: (prt2_adv.b = prt1_adv.a)
+ Filter: (((175) = prt1_adv.a) OR ((425) = prt2_adv.b))
+ -> Append
+ -> Seq Scan on prt2_adv_p1 prt2_adv_1
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p2 prt2_adv_2
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p3_1 prt2_adv_3
+ Filter: (a = 0)
+ -> Seq Scan on prt2_adv_p3_2 prt2_adv_4
+ Filter: (a = 0)
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p1 prt1_adv_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p2 prt1_adv_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 prt1_adv_3
+ Filter: (b = 0)
+(22 rows)
+
+DROP TABLE prt2_adv_p3_1;
+DROP TABLE prt2_adv_p3_2;
+ANALYZE prt2_adv;
+-- Test default partitions
+ALTER TABLE prt1_adv DETACH PARTITION prt1_adv_p1;
+-- Change prt1_adv_p1 to the default partition
+ALTER TABLE prt1_adv ATTACH PARTITION prt1_adv_p1 DEFAULT;
+ALTER TABLE prt1_adv DETACH PARTITION prt1_adv_p3;
+ANALYZE prt1_adv;
+-- We can do partitioned join even if only one of relations has the default
+-- partition
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_2
+ Filter: (b = 0)
+ -> Hash Join
+ Hash Cond: (t2_2.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_1
+ Filter: (b = 0)
+(15 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+(6 rows)
+
+-- Restore prt1_adv_p3
+ALTER TABLE prt1_adv ATTACH PARTITION prt1_adv_p3 FOR VALUES FROM (300) TO (400);
+ANALYZE prt1_adv;
+-- Restore prt2_adv_p3
+ALTER TABLE prt2_adv ATTACH PARTITION prt2_adv_p3 FOR VALUES FROM (350) TO (500);
+ANALYZE prt2_adv;
+-- Partitioned join can't be applied because the default partition of prt1_adv
+-- matches prt2_adv_p1 and prt2_adv_p3
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE 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_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p2 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p1 t1_3
+ Filter: (b = 0)
+(16 rows)
+
+ALTER TABLE prt2_adv DETACH PARTITION prt2_adv_p3;
+-- Change prt2_adv_p3 to the default partition
+ALTER TABLE prt2_adv ATTACH PARTITION prt2_adv_p3 DEFAULT;
+ANALYZE prt2_adv;
+-- Partitioned join can't be applied because the default partition of prt1_adv
+-- matches prt2_adv_p1 and prt2_adv_p3
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE 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_adv_p1 t2_1
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Seq Scan on prt2_adv_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on prt1_adv_p2 t1_1
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p3 t1_2
+ Filter: (b = 0)
+ -> Seq Scan on prt1_adv_p1 t1_3
+ Filter: (b = 0)
+(16 rows)
+
+DROP TABLE prt1_adv_p3;
+ANALYZE prt1_adv;
+DROP TABLE prt2_adv_p3;
+ANALYZE prt2_adv;
+CREATE TABLE prt3_adv (a int, b int, c varchar) PARTITION BY RANGE (a);
+CREATE TABLE prt3_adv_p1 PARTITION OF prt3_adv FOR VALUES FROM (200) TO (300);
+CREATE TABLE prt3_adv_p2 PARTITION OF prt3_adv FOR VALUES FROM (300) TO (400);
+CREATE INDEX prt3_adv_a_idx ON prt3_adv (a);
+INSERT INTO prt3_adv SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(200, 399) i;
+ANALYZE prt3_adv;
+-- 3-way join to test the default partition of a join relation
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a, t3.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) LEFT JOIN prt3_adv t3 ON (t1.a = t3.a) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a;
+ QUERY PLAN
+------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.b, t3.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: (t3_1.a = t1_1.a)
+ -> Seq Scan on prt3_adv_p1 t3_1
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: (t2_2.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_1
+ Filter: (b = 0)
+ -> Hash Right Join
+ Hash Cond: (t3_2.a = t1_2.a)
+ -> Seq Scan on prt3_adv_p2 t3_2
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: (t2_1.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_2
+ Filter: (b = 0)
+(23 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c, t3.a, t3.c FROM prt1_adv t1 LEFT JOIN prt2_adv t2 ON (t1.a = t2.b) LEFT JOIN prt3_adv t3 ON (t1.a = t3.a) WHERE t1.b = 0 ORDER BY t1.a, t2.b, t3.a;
+ a | c | b | c | a | c
+-----+------+-----+------+-----+------
+ 100 | 0100 | 100 | 0100 | |
+ 125 | 0125 | 125 | 0125 | |
+ 150 | 0150 | | | |
+ 175 | 0175 | | | |
+ 200 | 0200 | 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275 | 275 | 0275
+(8 rows)
+
+DROP TABLE prt1_adv;
+DROP TABLE prt2_adv;
+DROP TABLE prt3_adv;
+-- Test interaction of partitioned join with partition pruning
+CREATE TABLE prt1_adv (a int, b int, c varchar) PARTITION BY RANGE (a);
+CREATE TABLE prt1_adv_p1 PARTITION OF prt1_adv FOR VALUES FROM (100) TO (200);
+CREATE TABLE prt1_adv_p2 PARTITION OF prt1_adv FOR VALUES FROM (200) TO (300);
+CREATE TABLE prt1_adv_p3 PARTITION OF prt1_adv FOR VALUES FROM (300) TO (400);
+CREATE INDEX prt1_adv_a_idx ON prt1_adv (a);
+INSERT INTO prt1_adv SELECT i, i % 25, to_char(i, 'FM0000') FROM generate_series(100, 399) i;
+ANALYZE prt1_adv;
+CREATE TABLE prt2_adv (a int, b int, c varchar) PARTITION BY RANGE (b);
+CREATE TABLE prt2_adv_p1 PARTITION OF prt2_adv FOR VALUES FROM (100) TO (200);
+CREATE TABLE prt2_adv_p2 PARTITION OF prt2_adv FOR VALUES FROM (200) TO (400);
+CREATE INDEX prt2_adv_b_idx ON prt2_adv (b);
+INSERT INTO prt2_adv SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series(100, 399) i;
+ANALYZE prt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a < 300 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+-----------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: ((a < 300) AND (b = 0))
+ -> Hash Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: ((a < 300) AND (b = 0))
+(15 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a < 300 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 150 | 0150 | 150 | 0150
+ 175 | 0175 | 175 | 0175
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+(8 rows)
+
+DROP TABLE prt1_adv_p3;
+CREATE TABLE prt1_adv_default PARTITION OF prt1_adv DEFAULT;
+ANALYZE prt1_adv;
+CREATE TABLE prt2_adv_default PARTITION OF prt2_adv DEFAULT;
+ANALYZE prt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a >= 100 AND t1.a < 300 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: (t2_1.b = t1_1.a)
+ -> Seq Scan on prt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on prt1_adv_p1 t1_1
+ Filter: ((a >= 100) AND (a < 300) AND (b = 0))
+ -> Hash Join
+ Hash Cond: (t2_2.b = t1_2.a)
+ -> Seq Scan on prt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on prt1_adv_p2 t1_2
+ Filter: ((a >= 100) AND (a < 300) AND (b = 0))
+(15 rows)
+
+SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a >= 100 AND t1.a < 300 AND t1.b = 0 ORDER BY t1.a, t2.b;
+ a | c | b | c
+-----+------+-----+------
+ 100 | 0100 | 100 | 0100
+ 125 | 0125 | 125 | 0125
+ 150 | 0150 | 150 | 0150
+ 175 | 0175 | 175 | 0175
+ 200 | 0200 | 200 | 0200
+ 225 | 0225 | 225 | 0225
+ 250 | 0250 | 250 | 0250
+ 275 | 0275 | 275 | 0275
+(8 rows)
+
+DROP TABLE prt1_adv;
+DROP TABLE prt2_adv;
+-- Tests for list-partitioned tables
+CREATE TABLE plt1_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt1_adv_p1 PARTITION OF plt1_adv FOR VALUES IN ('0001', '0003');
+CREATE TABLE plt1_adv_p2 PARTITION OF plt1_adv FOR VALUES IN ('0004', '0006');
+CREATE TABLE plt1_adv_p3 PARTITION OF plt1_adv FOR VALUES IN ('0008', '0009');
+INSERT INTO plt1_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (1, 3, 4, 6, 8, 9);
+ANALYZE plt1_adv;
+CREATE TABLE plt2_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt2_adv_p1 PARTITION OF plt2_adv FOR VALUES IN ('0002', '0003');
+CREATE TABLE plt2_adv_p2 PARTITION OF plt2_adv FOR VALUES IN ('0004', '0006');
+CREATE TABLE plt2_adv_p3 PARTITION OF plt2_adv FOR VALUES IN ('0007', '0009');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 9 | 0009 | 9 | 0009
+(4 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t2_3
+(18 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+---+---+------
+ 3 | 3 | 0003
+ 4 | 4 | 0004
+ 6 | 6 | 0006
+ 9 | 9 | 0009
+(4 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+(6 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t2_3
+(18 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+---+---+------
+ 1 | 1 | 0001
+ 8 | 8 | 0008
+(2 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ Filter: ((COALESCE(t1_1.b, 0) < 10) AND (COALESCE(t2_1.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash Full Join
+ Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ Filter: ((COALESCE(t1_2.b, 0) < 10) AND (COALESCE(t2_2.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Hash
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash Full Join
+ Hash Cond: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ Filter: ((COALESCE(t1_3.b, 0) < 10) AND (COALESCE(t2_3.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ -> Hash
+ -> Seq Scan on plt2_adv_p3 t2_3
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ a | c | a | c
+---+------+---+------
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+ | | 2 | 0002
+ | | 7 | 0007
+(8 rows)
+
+-- Test cases where one side has an extra partition
+CREATE TABLE plt2_adv_extra PARTITION OF plt2_adv FOR VALUES IN ('0000');
+INSERT INTO plt2_adv_extra VALUES (0, 0, '0000');
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 9 | 0009 | 9 | 0009
+(4 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t2_3
+(18 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+---+---+------
+ 3 | 3 | 0003
+ 4 | 4 | 0004
+ 6 | 6 | 0006
+ 9 | 9 | 0009
+(4 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+(6 rows)
+
+-- left join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt2_adv t1 LEFT JOIN plt1_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+---------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Right Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t2_1
+ -> Seq Scan on plt1_adv_p2 t2_2
+ -> Seq Scan on plt1_adv_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on plt2_adv_extra t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t1_4
+ Filter: (b < 10)
+(18 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t2_3
+(18 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+---+---+------
+ 1 | 1 | 0001
+ 8 | 8 | 0008
+(2 rows)
+
+-- anti join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt2_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt1_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Anti Join
+ Hash Cond: ((t1.a = t2.a) AND (t1.c = t2.c))
+ -> Append
+ -> Seq Scan on plt2_adv_extra t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p1 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3 t1_4
+ Filter: (b < 10)
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t2_1
+ -> Seq Scan on plt1_adv_p2 t2_2
+ -> Seq Scan on plt1_adv_p3 t2_3
+(18 rows)
+
+-- full join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Hash Full Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ Filter: ((COALESCE(t1.b, 0) < 10) AND (COALESCE(t2.b, 0) < 10))
+ -> Append
+ -> Seq Scan on plt2_adv_extra t2_1
+ -> Seq Scan on plt2_adv_p1 t2_2
+ -> Seq Scan on plt2_adv_p2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Seq Scan on plt1_adv_p3 t1_3
+(15 rows)
+
+DROP TABLE plt2_adv_extra;
+-- Test cases where a partition on one side matches multiple partitions on
+-- the other side; we currently can't do partitioned join in such cases
+ALTER TABLE plt2_adv DETACH PARTITION plt2_adv_p2;
+-- Split plt2_adv_p2 into two partitions so that plt1_adv_p2 matches both
+CREATE TABLE plt2_adv_p2_1 PARTITION OF plt2_adv FOR VALUES IN ('0004');
+CREATE TABLE plt2_adv_p2_2 PARTITION OF plt2_adv FOR VALUES IN ('0006');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (4, 6);
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_1 t2_2
+ -> Seq Scan on plt2_adv_p2_2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(17 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Semi Join
+ Hash Cond: ((t1.a = t2.a) AND (t1.c = t2.c))
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Hash
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_1 t2_2
+ -> Seq Scan on plt2_adv_p2_2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+(17 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Right Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_1 t2_2
+ -> Seq Scan on plt2_adv_p2_2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(17 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Anti Join
+ Hash Cond: ((t1.a = t2.a) AND (t1.c = t2.c))
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Hash
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_1 t2_2
+ -> Seq Scan on plt2_adv_p2_2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+(17 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Hash Full Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ Filter: ((COALESCE(t1.b, 0) < 10) AND (COALESCE(t2.b, 0) < 10))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_1 t2_2
+ -> Seq Scan on plt2_adv_p2_2 t2_3
+ -> Seq Scan on plt2_adv_p3 t2_4
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Seq Scan on plt1_adv_p3 t1_3
+(15 rows)
+
+DROP TABLE plt2_adv_p2_1;
+DROP TABLE plt2_adv_p2_2;
+-- Restore plt2_adv_p2
+ALTER TABLE plt2_adv ATTACH PARTITION plt2_adv_p2 FOR VALUES IN ('0004', '0006');
+-- Test NULL partitions
+ALTER TABLE plt1_adv DETACH PARTITION plt1_adv_p1;
+-- Change plt1_adv_p1 to the NULL partition
+CREATE TABLE plt1_adv_p1_null PARTITION OF plt1_adv FOR VALUES IN (NULL, '0001', '0003');
+INSERT INTO plt1_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (1, 3);
+INSERT INTO plt1_adv VALUES (-1, -1, NULL);
+ANALYZE plt1_adv;
+ALTER TABLE plt2_adv DETACH PARTITION plt2_adv_p3;
+-- Change plt2_adv_p3 to the NULL partition
+CREATE TABLE plt2_adv_p3_null PARTITION OF plt2_adv FOR VALUES IN (NULL, '0007', '0009');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (7, 9);
+INSERT INTO plt2_adv VALUES (-1, -1, NULL);
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1_null t1_1
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3_null t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 9 | 0009 | 9 | 0009
+(4 rows)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Semi Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1_null t1_1
+ Filter: (b < 10)
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Semi Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3_null t2_3
+(19 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+---+---+------
+ 3 | 3 | 0003
+ 4 | 4 | 0004
+ 6 | 6 | 0006
+ 9 | 9 | 0009
+(4 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1_null t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3_null t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+----+------+---+------
+ -1 | | |
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+(7 rows)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Anti Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on plt1_adv_p1_null t1_1
+ Filter: (b < 10)
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Nested Loop Anti Join
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_p3_null t2_3
+(19 rows)
+
+SELECT t1.* FROM plt1_adv t1 WHERE NOT EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a;
+ a | b | c
+----+----+------
+ -1 | -1 |
+ 1 | 1 | 0001
+ 8 | 8 | 0008
+(3 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ Filter: ((COALESCE(t1_1.b, 0) < 10) AND (COALESCE(t2_1.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p1_null t1_1
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash Full Join
+ Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ Filter: ((COALESCE(t1_2.b, 0) < 10) AND (COALESCE(t2_2.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Hash
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash Full Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ Filter: ((COALESCE(t1_3.b, 0) < 10) AND (COALESCE(t2_3.b, 0) < 10))
+ -> Seq Scan on plt2_adv_p3_null t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ a | c | a | c
+----+------+----+------
+ -1 | | |
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+ | | -1 |
+ | | 2 | 0002
+ | | 7 | 0007
+(10 rows)
+
+DROP TABLE plt1_adv_p1_null;
+-- Restore plt1_adv_p1
+ALTER TABLE plt1_adv ATTACH PARTITION plt1_adv_p1 FOR VALUES IN ('0001', '0003');
+-- Add to plt1_adv the extra NULL partition containing only NULL values as the
+-- key values
+CREATE TABLE plt1_adv_extra PARTITION OF plt1_adv FOR VALUES IN (NULL);
+INSERT INTO plt1_adv VALUES (-1, -1, NULL);
+ANALYZE plt1_adv;
+DROP TABLE plt2_adv_p3_null;
+-- Restore plt2_adv_p3
+ALTER TABLE plt2_adv ATTACH PARTITION plt2_adv_p3 FOR VALUES IN ('0007', '0009');
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 9 | 0009 | 9 | 0009
+(4 rows)
+
+-- left join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+---------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Right Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_extra t1_4
+ Filter: (b < 10)
+(18 rows)
+
+-- full join; currently we can't do partitioned join if there are no matched
+-- partitions on the nullable side
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Hash Full Join
+ Hash Cond: ((t1.a = t2.a) AND (t1.c = t2.c))
+ Filter: ((COALESCE(t1.b, 0) < 10) AND (COALESCE(t2.b, 0) < 10))
+ -> Append
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Seq Scan on plt1_adv_p3 t1_3
+ -> Seq Scan on plt1_adv_extra t1_4
+ -> Hash
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Seq Scan on plt2_adv_p3 t2_3
+(15 rows)
+
+-- Add to plt2_adv the extra NULL partition containing only NULL values as the
+-- key values
+CREATE TABLE plt2_adv_extra PARTITION OF plt2_adv FOR VALUES IN (NULL);
+INSERT INTO plt2_adv VALUES (-1, -1, NULL);
+ANALYZE plt2_adv;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+(21 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 9 | 0009 | 9 | 0009
+(4 rows)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Nested Loop Left Join
+ Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c))
+ -> Seq Scan on plt1_adv_extra t1_4
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_extra t2_4
+(26 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+----+------+---+------
+ -1 | | |
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+(7 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t2.a
+ -> Append
+ -> Hash Full Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c))
+ Filter: ((COALESCE(t1_1.b, 0) < 10) AND (COALESCE(t2_1.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash Full Join
+ Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ Filter: ((COALESCE(t1_2.b, 0) < 10) AND (COALESCE(t2_2.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Hash
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash Full Join
+ Hash Cond: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c))
+ Filter: ((COALESCE(t1_3.b, 0) < 10) AND (COALESCE(t2_3.b, 0) < 10))
+ -> Seq Scan on plt1_adv_p3 t1_3
+ -> Hash
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash Full Join
+ Hash Cond: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c))
+ Filter: ((COALESCE(t1_4.b, 0) < 10) AND (COALESCE(t2_4.b, 0) < 10))
+ -> Seq Scan on plt1_adv_extra t1_4
+ -> Hash
+ -> Seq Scan on plt2_adv_extra t2_4
+(27 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 FULL JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE coalesce(t1.b, 0) < 10 AND coalesce(t2.b, 0) < 10 ORDER BY t1.a, t2.a;
+ a | c | a | c
+----+------+----+------
+ -1 | | |
+ 1 | 0001 | |
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+ 8 | 0008 | |
+ 9 | 0009 | 9 | 0009
+ | | -1 |
+ | | 2 | 0002
+ | | 7 | 0007
+(10 rows)
+
+-- 3-way join to test the NULL partition of a join relation
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) LEFT JOIN plt1_adv t3 ON (t1.a = t3.a AND t1.c = t3.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t3_1.a = t1_1.a) AND (t3_1.c = t1_1.c))
+ -> Seq Scan on plt1_adv_p1 t3_1
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t3_2.a = t1_2.a) AND (t3_2.c = t1_2.c))
+ -> Seq Scan on plt1_adv_p2 t3_2
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_2
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t3_3.a = t1_3.a) AND (t3_3.c = t1_3.c))
+ -> Seq Scan on plt1_adv_p3 t3_3
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c))
+ -> Seq Scan on plt2_adv_p3 t2_3
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_3
+ Filter: (b < 10)
+ -> Nested Loop Left Join
+ Join Filter: ((t1_4.a = t3_4.a) AND (t1_4.c = t3_4.c))
+ -> Nested Loop Left Join
+ Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c))
+ -> Seq Scan on plt1_adv_extra t1_4
+ Filter: (b < 10)
+ -> Seq Scan on plt2_adv_extra t2_4
+ -> Seq Scan on plt1_adv_extra t3_4
+(41 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) LEFT JOIN plt1_adv t3 ON (t1.a = t3.a AND t1.c = t3.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c | a | c
+----+------+---+------+---+------
+ -1 | | | | |
+ 1 | 0001 | | | 1 | 0001
+ 3 | 0003 | 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006 | 6 | 0006
+ 8 | 0008 | | | 8 | 0008
+ 9 | 0009 | 9 | 0009 | 9 | 0009
+(7 rows)
+
+DROP TABLE plt1_adv_extra;
+DROP TABLE plt2_adv_extra;
+-- Test default partitions
+ALTER TABLE plt1_adv DETACH PARTITION plt1_adv_p1;
+-- Change plt1_adv_p1 to the default partition
+ALTER TABLE plt1_adv ATTACH PARTITION plt1_adv_p1 DEFAULT;
+DROP TABLE plt1_adv_p3;
+ANALYZE plt1_adv;
+DROP TABLE plt2_adv_p3;
+ANALYZE plt2_adv;
+-- We can do partitioned join even if only one of relations has the default
+-- partition
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_2.a) AND (t2_1.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_1.a) AND (t2_2.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_1
+ Filter: (b < 10)
+(15 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+(3 rows)
+
+ALTER TABLE plt2_adv DETACH PARTITION plt2_adv_p2;
+-- Change plt2_adv_p2 to contain '0005' in addition to '0004' and '0006' as
+-- the key values
+CREATE TABLE plt2_adv_p2_ext PARTITION OF plt2_adv FOR VALUES IN ('0004', '0005', '0006');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (4, 5, 6);
+ANALYZE plt2_adv;
+-- Partitioned join can't be applied because the default partition of plt1_adv
+-- matches plt2_adv_p1 and plt2_adv_p2_ext
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_ext t2_2
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p2 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p1 t1_2
+ Filter: (b < 10)
+(13 rows)
+
+ALTER TABLE plt2_adv DETACH PARTITION plt2_adv_p2_ext;
+-- Change plt2_adv_p2_ext to the default partition
+ALTER TABLE plt2_adv ATTACH PARTITION plt2_adv_p2_ext DEFAULT;
+ANALYZE plt2_adv;
+-- Partitioned join can't be applied because the default partition of plt1_adv
+-- matches plt2_adv_p1 and plt2_adv_p2_ext
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Append
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Seq Scan on plt2_adv_p2_ext t2_2
+ -> Hash
+ -> Append
+ -> Seq Scan on plt1_adv_p2 t1_1
+ Filter: (b < 10)
+ -> Seq Scan on plt1_adv_p1 t1_2
+ Filter: (b < 10)
+(13 rows)
+
+DROP TABLE plt2_adv_p2_ext;
+-- Restore plt2_adv_p2
+ALTER TABLE plt2_adv ATTACH PARTITION plt2_adv_p2 FOR VALUES IN ('0004', '0006');
+ANALYZE plt2_adv;
+CREATE TABLE plt3_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt3_adv_p1 PARTITION OF plt3_adv FOR VALUES IN ('0004', '0006');
+CREATE TABLE plt3_adv_p2 PARTITION OF plt3_adv FOR VALUES IN ('0007', '0009');
+INSERT INTO plt3_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (4, 6, 7, 9);
+ANALYZE plt3_adv;
+-- 3-way join to test the default partition of a join relation
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) LEFT JOIN plt3_adv t3 ON (t1.a = t3.a AND t1.c = t3.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Right Join
+ Hash Cond: ((t3_1.a = t1_1.a) AND (t3_1.c = t1_1.c))
+ -> Seq Scan on plt3_adv_p1 t3_1
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: ((t2_2.a = t1_1.a) AND (t2_2.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_1
+ Filter: (b < 10)
+ -> Hash Right Join
+ Hash Cond: ((t3_2.a = t1_2.a) AND (t3_2.c = t1_2.c))
+ -> Seq Scan on plt3_adv_p2 t3_2
+ -> Hash
+ -> Hash Right Join
+ Hash Cond: ((t2_1.a = t1_2.a) AND (t2_1.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_2
+ Filter: (b < 10)
+(23 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) LEFT JOIN plt3_adv t3 ON (t1.a = t3.a AND t1.c = t3.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c | a | c
+---+------+---+------+---+------
+ 1 | 0001 | | | |
+ 3 | 0003 | 3 | 0003 | |
+ 4 | 0004 | 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006 | 6 | 0006
+(4 rows)
+
+-- Test cases where one side has the default partition while the other side
+-- has the NULL partition
+DROP TABLE plt2_adv_p1;
+-- Add the NULL partition to plt2_adv
+CREATE TABLE plt2_adv_p1_null PARTITION OF plt2_adv FOR VALUES IN (NULL, '0001', '0003');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (1, 3);
+INSERT INTO plt2_adv VALUES (-1, -1, NULL);
+ANALYZE plt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_2.a) AND (t2_1.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p1_null t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p1 t1_2
+ Filter: (b < 10)
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_1.a) AND (t2_2.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1_1
+ Filter: (b < 10)
+(15 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 1 | 0001 | 1 | 0001
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+(4 rows)
+
+DROP TABLE plt2_adv_p1_null;
+-- Add the NULL partition that contains only NULL values as the key values
+CREATE TABLE plt2_adv_p1_null PARTITION OF plt2_adv FOR VALUES IN (NULL);
+INSERT INTO plt2_adv VALUES (-1, -1, NULL);
+ANALYZE plt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Seq Scan on plt2_adv_p2 t2
+ -> Hash
+ -> Seq Scan on plt1_adv_p2 t1
+ Filter: (b < 10)
+(8 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 4 | 0004 | 4 | 0004
+ 6 | 0006 | 6 | 0006
+(2 rows)
+
+DROP TABLE plt1_adv;
+DROP TABLE plt2_adv;
+DROP TABLE plt3_adv;
+-- Test interaction of partitioned join with partition pruning
+CREATE TABLE plt1_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt1_adv_p1 PARTITION OF plt1_adv FOR VALUES IN ('0001');
+CREATE TABLE plt1_adv_p2 PARTITION OF plt1_adv FOR VALUES IN ('0002');
+CREATE TABLE plt1_adv_p3 PARTITION OF plt1_adv FOR VALUES IN ('0003');
+CREATE TABLE plt1_adv_p4 PARTITION OF plt1_adv FOR VALUES IN (NULL, '0004', '0005');
+INSERT INTO plt1_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (1, 2, 3, 4, 5);
+INSERT INTO plt1_adv VALUES (-1, -1, NULL);
+ANALYZE plt1_adv;
+CREATE TABLE plt2_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt2_adv_p1 PARTITION OF plt2_adv FOR VALUES IN ('0001', '0002');
+CREATE TABLE plt2_adv_p2 PARTITION OF plt2_adv FOR VALUES IN (NULL);
+CREATE TABLE plt2_adv_p3 PARTITION OF plt2_adv FOR VALUES IN ('0003');
+CREATE TABLE plt2_adv_p4 PARTITION OF plt2_adv FOR VALUES IN ('0004', '0005');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 10, 'FM0000') FROM generate_series(1, 299) i WHERE i % 10 IN (1, 2, 3, 4, 5);
+INSERT INTO plt2_adv VALUES (-1, -1, NULL);
+ANALYZE plt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p3 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_1
+ Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[])))
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p4 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p4 t1_2
+ Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[])))
+(15 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 5 | 0005 | 5 | 0005
+(3 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IS NULL AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Right Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Seq Scan on plt2_adv_p4 t2
+ -> Hash
+ -> Seq Scan on plt1_adv_p4 t1
+ Filter: ((c IS NULL) AND (b < 10))
+(8 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IS NULL AND t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+----+---+---+---
+ -1 | | |
+(1 row)
+
+CREATE TABLE plt1_adv_default PARTITION OF plt1_adv DEFAULT;
+ANALYZE plt1_adv;
+CREATE TABLE plt2_adv_default PARTITION OF plt2_adv DEFAULT;
+ANALYZE plt2_adv;
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c))
+ -> Seq Scan on plt2_adv_p3 t2_1
+ -> Hash
+ -> Seq Scan on plt1_adv_p3 t1_1
+ Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[])))
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c))
+ -> Seq Scan on plt2_adv_p4 t2_2
+ -> Hash
+ -> Seq Scan on plt1_adv_p4 t1_2
+ Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[])))
+(15 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IN ('0003', '0004', '0005') AND t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+---+------+---+------
+ 3 | 0003 | 3 | 0003
+ 4 | 0004 | 4 | 0004
+ 5 | 0005 | 5 | 0005
+(3 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IS NULL AND t1.b < 10 ORDER BY t1.a;
+ QUERY PLAN
+--------------------------------------------------------
+ Sort
+ Sort Key: t1.a
+ -> Hash Right Join
+ Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c))
+ -> Seq Scan on plt2_adv_p4 t2
+ -> Hash
+ -> Seq Scan on plt1_adv_p4 t1
+ Filter: ((c IS NULL) AND (b < 10))
+(8 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.c IS NULL AND t1.b < 10 ORDER BY t1.a;
+ a | c | a | c
+----+---+---+---
+ -1 | | |
+(1 row)
+
+DROP TABLE plt1_adv;
+DROP TABLE plt2_adv;
+-- Test the process_outer_partition() code path
+CREATE TABLE plt1_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt1_adv_p1 PARTITION OF plt1_adv FOR VALUES IN ('0000', '0001', '0002');
+CREATE TABLE plt1_adv_p2 PARTITION OF plt1_adv FOR VALUES IN ('0003', '0004');
+INSERT INTO plt1_adv SELECT i, i, to_char(i % 5, 'FM0000') FROM generate_series(0, 24) i;
+ANALYZE plt1_adv;
+CREATE TABLE plt2_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt2_adv_p1 PARTITION OF plt2_adv FOR VALUES IN ('0002');
+CREATE TABLE plt2_adv_p2 PARTITION OF plt2_adv FOR VALUES IN ('0003', '0004');
+INSERT INTO plt2_adv SELECT i, i, to_char(i % 5, 'FM0000') FROM generate_series(0, 24) i WHERE i % 5 IN (2, 3, 4);
+ANALYZE plt2_adv;
+CREATE TABLE plt3_adv (a int, b int, c text) PARTITION BY LIST (c);
+CREATE TABLE plt3_adv_p1 PARTITION OF plt3_adv FOR VALUES IN ('0001');
+CREATE TABLE plt3_adv_p2 PARTITION OF plt3_adv FOR VALUES IN ('0003', '0004');
+INSERT INTO plt3_adv SELECT i, i, to_char(i % 5, 'FM0000') FROM generate_series(0, 24) i WHERE i % 5 IN (1, 3, 4);
+ANALYZE plt3_adv;
+-- This tests that when merging partitions from plt1_adv and plt2_adv in
+-- merge_list_bounds(), process_outer_partition() returns an already-assigned
+-- merged partition when re-called with plt1_adv_p1 for the second list value
+-- '0001' of that partition
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM (plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.c = t2.c)) FULL JOIN plt3_adv t3 ON (t1.c = t3.c) WHERE coalesce(t1.a, 0) % 5 != 3 AND coalesce(t1.a, 0) % 5 != 4 ORDER BY t1.c, t1.a, t2.a, t3.a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.c, t1.a, t2.a, t3.a
+ -> Append
+ -> Hash Full Join
+ Hash Cond: (t1_1.c = t3_1.c)
+ Filter: (((COALESCE(t1_1.a, 0) % 5) <> 3) AND ((COALESCE(t1_1.a, 0) % 5) <> 4))
+ -> Hash Left Join
+ Hash Cond: (t1_1.c = t2_1.c)
+ -> Seq Scan on plt1_adv_p1 t1_1
+ -> Hash
+ -> Seq Scan on plt2_adv_p1 t2_1
+ -> Hash
+ -> Seq Scan on plt3_adv_p1 t3_1
+ -> Hash Full Join
+ Hash Cond: (t1_2.c = t3_2.c)
+ Filter: (((COALESCE(t1_2.a, 0) % 5) <> 3) AND ((COALESCE(t1_2.a, 0) % 5) <> 4))
+ -> Hash Left Join
+ Hash Cond: (t1_2.c = t2_2.c)
+ -> Seq Scan on plt1_adv_p2 t1_2
+ -> Hash
+ -> Seq Scan on plt2_adv_p2 t2_2
+ -> Hash
+ -> Seq Scan on plt3_adv_p2 t3_2
+(23 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM (plt1_adv t1 LEFT JOIN plt2_adv t2 ON (t1.c = t2.c)) FULL JOIN plt3_adv t3 ON (t1.c = t3.c) WHERE coalesce(t1.a, 0) % 5 != 3 AND coalesce(t1.a, 0) % 5 != 4 ORDER BY t1.c, t1.a, t2.a, t3.a;
+ a | c | a | c | a | c
+----+------+----+------+----+------
+ 0 | 0000 | | | |
+ 5 | 0000 | | | |
+ 10 | 0000 | | | |
+ 15 | 0000 | | | |
+ 20 | 0000 | | | |
+ 1 | 0001 | | | 1 | 0001
+ 1 | 0001 | | | 6 | 0001
+ 1 | 0001 | | | 11 | 0001
+ 1 | 0001 | | | 16 | 0001
+ 1 | 0001 | | | 21 | 0001
+ 6 | 0001 | | | 1 | 0001
+ 6 | 0001 | | | 6 | 0001
+ 6 | 0001 | | | 11 | 0001
+ 6 | 0001 | | | 16 | 0001
+ 6 | 0001 | | | 21 | 0001
+ 11 | 0001 | | | 1 | 0001
+ 11 | 0001 | | | 6 | 0001
+ 11 | 0001 | | | 11 | 0001
+ 11 | 0001 | | | 16 | 0001
+ 11 | 0001 | | | 21 | 0001
+ 16 | 0001 | | | 1 | 0001
+ 16 | 0001 | | | 6 | 0001
+ 16 | 0001 | | | 11 | 0001
+ 16 | 0001 | | | 16 | 0001
+ 16 | 0001 | | | 21 | 0001
+ 21 | 0001 | | | 1 | 0001
+ 21 | 0001 | | | 6 | 0001
+ 21 | 0001 | | | 11 | 0001
+ 21 | 0001 | | | 16 | 0001
+ 21 | 0001 | | | 21 | 0001
+ 2 | 0002 | 2 | 0002 | |
+ 2 | 0002 | 7 | 0002 | |
+ 2 | 0002 | 12 | 0002 | |
+ 2 | 0002 | 17 | 0002 | |
+ 2 | 0002 | 22 | 0002 | |
+ 7 | 0002 | 2 | 0002 | |
+ 7 | 0002 | 7 | 0002 | |
+ 7 | 0002 | 12 | 0002 | |
+ 7 | 0002 | 17 | 0002 | |
+ 7 | 0002 | 22 | 0002 | |
+ 12 | 0002 | 2 | 0002 | |
+ 12 | 0002 | 7 | 0002 | |
+ 12 | 0002 | 12 | 0002 | |
+ 12 | 0002 | 17 | 0002 | |
+ 12 | 0002 | 22 | 0002 | |
+ 17 | 0002 | 2 | 0002 | |
+ 17 | 0002 | 7 | 0002 | |
+ 17 | 0002 | 12 | 0002 | |
+ 17 | 0002 | 17 | 0002 | |
+ 17 | 0002 | 22 | 0002 | |
+ 22 | 0002 | 2 | 0002 | |
+ 22 | 0002 | 7 | 0002 | |
+ 22 | 0002 | 12 | 0002 | |
+ 22 | 0002 | 17 | 0002 | |
+ 22 | 0002 | 22 | 0002 | |
+(55 rows)
+
+DROP TABLE plt1_adv;
+DROP TABLE plt2_adv;
+DROP TABLE plt3_adv;
+-- Tests for multi-level partitioned tables
+CREATE TABLE alpha (a double precision, b int, c text) PARTITION BY RANGE (a);
+CREATE TABLE alpha_neg PARTITION OF alpha FOR VALUES FROM ('-Infinity') TO (0) PARTITION BY RANGE (b);
+CREATE TABLE alpha_pos PARTITION OF alpha FOR VALUES FROM (0) TO (10.0) PARTITION BY LIST (c);
+CREATE TABLE alpha_neg_p1 PARTITION OF alpha_neg FOR VALUES FROM (100) TO (200);
+CREATE TABLE alpha_neg_p2 PARTITION OF alpha_neg FOR VALUES FROM (200) TO (300);
+CREATE TABLE alpha_neg_p3 PARTITION OF alpha_neg FOR VALUES FROM (300) TO (400);
+CREATE TABLE alpha_pos_p1 PARTITION OF alpha_pos FOR VALUES IN ('0001', '0003');
+CREATE TABLE alpha_pos_p2 PARTITION OF alpha_pos FOR VALUES IN ('0004', '0006');
+CREATE TABLE alpha_pos_p3 PARTITION OF alpha_pos FOR VALUES IN ('0008', '0009');
+INSERT INTO alpha_neg SELECT -1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(100, 399) i WHERE i % 10 IN (1, 3, 4, 6, 8, 9);
+INSERT INTO alpha_pos SELECT 1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(100, 399) i WHERE i % 10 IN (1, 3, 4, 6, 8, 9);
+ANALYZE alpha;
+CREATE TABLE beta (a double precision, b int, c text) PARTITION BY RANGE (a);
+CREATE TABLE beta_neg PARTITION OF beta FOR VALUES FROM (-10.0) TO (0) PARTITION BY RANGE (b);
+CREATE TABLE beta_pos PARTITION OF beta FOR VALUES FROM (0) TO ('Infinity') PARTITION BY LIST (c);
+CREATE TABLE beta_neg_p1 PARTITION OF beta_neg FOR VALUES FROM (100) TO (150);
+CREATE TABLE beta_neg_p2 PARTITION OF beta_neg FOR VALUES FROM (200) TO (300);
+CREATE TABLE beta_neg_p3 PARTITION OF beta_neg FOR VALUES FROM (350) TO (500);
+CREATE TABLE beta_pos_p1 PARTITION OF beta_pos FOR VALUES IN ('0002', '0003');
+CREATE TABLE beta_pos_p2 PARTITION OF beta_pos FOR VALUES IN ('0004', '0006');
+CREATE TABLE beta_pos_p3 PARTITION OF beta_pos FOR VALUES IN ('0007', '0009');
+INSERT INTO beta_neg SELECT -1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(100, 149) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+INSERT INTO beta_neg SELECT -1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(200, 299) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+INSERT INTO beta_neg SELECT -1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(350, 499) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+INSERT INTO beta_pos SELECT 1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(100, 149) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+INSERT INTO beta_pos SELECT 1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(200, 299) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+INSERT INTO beta_pos SELECT 1.0, i, to_char(i % 10, 'FM0000') FROM generate_series(350, 499) i WHERE i % 10 IN (2, 3, 4, 6, 7, 9);
+ANALYZE beta;
+EXPLAIN (COSTS OFF)
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b) WHERE t1.b >= 125 AND t1.b < 225 ORDER BY t1.a, t1.b;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t1.b
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b))
+ -> Seq Scan on alpha_neg_p1 t1_1
+ Filter: ((b >= 125) AND (b < 225))
+ -> Hash
+ -> Seq Scan on beta_neg_p1 t2_1
+ -> Hash Join
+ Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.b = t1_2.b))
+ -> Seq Scan on beta_neg_p2 t2_2
+ -> Hash
+ -> Seq Scan on alpha_neg_p2 t1_2
+ Filter: ((b >= 125) AND (b < 225))
+ -> Hash Join
+ Hash Cond: ((t2_4.a = t1_4.a) AND (t2_4.b = t1_4.b))
+ -> Append
+ -> Seq Scan on beta_pos_p1 t2_4
+ -> Seq Scan on beta_pos_p2 t2_5
+ -> Seq Scan on beta_pos_p3 t2_6
+ -> Hash
+ -> Append
+ -> Seq Scan on alpha_pos_p1 t1_4
+ Filter: ((b >= 125) AND (b < 225))
+ -> Seq Scan on alpha_pos_p2 t1_5
+ Filter: ((b >= 125) AND (b < 225))
+ -> Seq Scan on alpha_pos_p3 t1_6
+ Filter: ((b >= 125) AND (b < 225))
+(29 rows)
+
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b) WHERE t1.b >= 125 AND t1.b < 225 ORDER BY t1.a, t1.b;
+ a | b | c | a | b | c
+----+-----+------+----+-----+------
+ -1 | 126 | 0006 | -1 | 126 | 0006
+ -1 | 129 | 0009 | -1 | 129 | 0009
+ -1 | 133 | 0003 | -1 | 133 | 0003
+ -1 | 134 | 0004 | -1 | 134 | 0004
+ -1 | 136 | 0006 | -1 | 136 | 0006
+ -1 | 139 | 0009 | -1 | 139 | 0009
+ -1 | 143 | 0003 | -1 | 143 | 0003
+ -1 | 144 | 0004 | -1 | 144 | 0004
+ -1 | 146 | 0006 | -1 | 146 | 0006
+ -1 | 149 | 0009 | -1 | 149 | 0009
+ -1 | 203 | 0003 | -1 | 203 | 0003
+ -1 | 204 | 0004 | -1 | 204 | 0004
+ -1 | 206 | 0006 | -1 | 206 | 0006
+ -1 | 209 | 0009 | -1 | 209 | 0009
+ -1 | 213 | 0003 | -1 | 213 | 0003
+ -1 | 214 | 0004 | -1 | 214 | 0004
+ -1 | 216 | 0006 | -1 | 216 | 0006
+ -1 | 219 | 0009 | -1 | 219 | 0009
+ -1 | 223 | 0003 | -1 | 223 | 0003
+ -1 | 224 | 0004 | -1 | 224 | 0004
+ 1 | 126 | 0006 | 1 | 126 | 0006
+ 1 | 129 | 0009 | 1 | 129 | 0009
+ 1 | 133 | 0003 | 1 | 133 | 0003
+ 1 | 134 | 0004 | 1 | 134 | 0004
+ 1 | 136 | 0006 | 1 | 136 | 0006
+ 1 | 139 | 0009 | 1 | 139 | 0009
+ 1 | 143 | 0003 | 1 | 143 | 0003
+ 1 | 144 | 0004 | 1 | 144 | 0004
+ 1 | 146 | 0006 | 1 | 146 | 0006
+ 1 | 149 | 0009 | 1 | 149 | 0009
+ 1 | 203 | 0003 | 1 | 203 | 0003
+ 1 | 204 | 0004 | 1 | 204 | 0004
+ 1 | 206 | 0006 | 1 | 206 | 0006
+ 1 | 209 | 0009 | 1 | 209 | 0009
+ 1 | 213 | 0003 | 1 | 213 | 0003
+ 1 | 214 | 0004 | 1 | 214 | 0004
+ 1 | 216 | 0006 | 1 | 216 | 0006
+ 1 | 219 | 0009 | 1 | 219 | 0009
+ 1 | 223 | 0003 | 1 | 223 | 0003
+ 1 | 224 | 0004 | 1 | 224 | 0004
+(40 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b, t2.b;
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t1.b, t2.b
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c))
+ -> Append
+ -> Seq Scan on alpha_neg_p1 t1_2
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Seq Scan on alpha_neg_p2 t1_3
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Hash
+ -> Append
+ -> Seq Scan on beta_neg_p1 t2_2
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Seq Scan on beta_neg_p2 t2_3
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Nested Loop
+ Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c))
+ -> Seq Scan on alpha_pos_p2 t1_4
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Seq Scan on beta_pos_p2 t2_4
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Nested Loop
+ Join Filter: ((t1_5.a = t2_5.a) AND (t1_5.c = t2_5.c))
+ -> Seq Scan on alpha_pos_p3 t1_5
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Seq Scan on beta_pos_p3 t2_5
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+(28 rows)
+
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b, t2.b;
+ a | b | c | a | b | c
+----+-----+------+----+-----+------
+ -1 | 104 | 0004 | -1 | 104 | 0004
+ -1 | 104 | 0004 | -1 | 204 | 0004
+ -1 | 109 | 0009 | -1 | 109 | 0009
+ -1 | 109 | 0009 | -1 | 209 | 0009
+ -1 | 204 | 0004 | -1 | 104 | 0004
+ -1 | 204 | 0004 | -1 | 204 | 0004
+ -1 | 209 | 0009 | -1 | 109 | 0009
+ -1 | 209 | 0009 | -1 | 209 | 0009
+ 1 | 104 | 0004 | 1 | 104 | 0004
+ 1 | 104 | 0004 | 1 | 204 | 0004
+ 1 | 109 | 0009 | 1 | 109 | 0009
+ 1 | 109 | 0009 | 1 | 209 | 0009
+ 1 | 204 | 0004 | 1 | 104 | 0004
+ 1 | 204 | 0004 | 1 | 204 | 0004
+ 1 | 209 | 0009 | 1 | 109 | 0009
+ 1 | 209 | 0009 | 1 | 209 | 0009
+(16 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b;
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.a, t1.b
+ -> Append
+ -> Hash Join
+ Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c))
+ -> Seq Scan on alpha_neg_p1 t1_1
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Hash
+ -> Seq Scan on beta_neg_p1 t2_1
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Hash Join
+ Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c))
+ -> Seq Scan on alpha_neg_p2 t1_2
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Hash
+ -> Seq Scan on beta_neg_p2 t2_2
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Nested Loop
+ Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.b = t2_3.b) AND (t1_3.c = t2_3.c))
+ -> Seq Scan on alpha_pos_p2 t1_3
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Seq Scan on beta_pos_p2 t2_3
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+ -> Nested Loop
+ Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.b = t2_4.b) AND (t1_4.c = t2_4.c))
+ -> Seq Scan on alpha_pos_p3 t1_4
+ Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))))
+ -> Seq Scan on beta_pos_p3 t2_4
+ Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210)))
+(29 rows)
+
+SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110) OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004', '0009') ORDER BY t1.a, t1.b;
+ a | b | c | a | b | c
+----+-----+------+----+-----+------
+ -1 | 104 | 0004 | -1 | 104 | 0004
+ -1 | 109 | 0009 | -1 | 109 | 0009
+ -1 | 204 | 0004 | -1 | 204 | 0004
+ -1 | 209 | 0009 | -1 | 209 | 0009
+ 1 | 104 | 0004 | 1 | 104 | 0004
+ 1 | 109 | 0009 | 1 | 109 | 0009
+ 1 | 204 | 0004 | 1 | 204 | 0004
+ 1 | 209 | 0009 | 1 | 209 | 0009
+(8 rows)
+
+-- partitionwise join with fractional paths
+CREATE TABLE fract_t (id BIGINT, PRIMARY KEY (id)) PARTITION BY RANGE (id);
+CREATE TABLE fract_t0 PARTITION OF fract_t FOR VALUES FROM ('0') TO ('1000');
+CREATE TABLE fract_t1 PARTITION OF fract_t FOR VALUES FROM ('1000') TO ('2000');
+-- insert data
+INSERT INTO fract_t (id) (SELECT generate_series(0, 1999));
+ANALYZE fract_t;
+-- verify plan; nested index only scans
+SET max_parallel_workers_per_gather = 0;
+SET enable_partitionwise_join = on;
+EXPLAIN (COSTS OFF)
+SELECT * FROM fract_t x LEFT JOIN fract_t y USING (id) ORDER BY id ASC LIMIT 10;
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Limit
+ -> Merge Append
+ Sort Key: x.id
+ -> Merge Left Join
+ Merge Cond: (x_1.id = y_1.id)
+ -> Index Only Scan using fract_t0_pkey on fract_t0 x_1
+ -> Index Only Scan using fract_t0_pkey on fract_t0 y_1
+ -> Merge Left Join
+ Merge Cond: (x_2.id = y_2.id)
+ -> Index Only Scan using fract_t1_pkey on fract_t1 x_2
+ -> Index Only Scan using fract_t1_pkey on fract_t1 y_2
+(11 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM fract_t x LEFT JOIN fract_t y USING (id) ORDER BY id DESC LIMIT 10;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> Merge Append
+ Sort Key: x.id DESC
+ -> Nested Loop Left Join
+ -> Index Only Scan Backward using fract_t0_pkey on fract_t0 x_1
+ -> Index Only Scan using fract_t0_pkey on fract_t0 y_1
+ Index Cond: (id = x_1.id)
+ -> Nested Loop Left Join
+ -> Index Only Scan Backward using fract_t1_pkey on fract_t1 x_2
+ -> Index Only Scan using fract_t1_pkey on fract_t1 y_2
+ Index Cond: (id = x_2.id)
+(11 rows)
+
+-- cleanup
+DROP TABLE fract_t;
+RESET max_parallel_workers_per_gather;
+RESET enable_partitionwise_join;