From 6201bbcfe36b1adcfa991b855fc6ab69e3fc7cb4 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Mon, 27 Jan 2020 18:14:58 -0800
Subject: [PATCH 2/3] Extending partition join tests.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Adding more tests of the partition-wise join logic.  The expected
output for the new tests is based on current behavior rather than
what I would necessarily like to see.  In particular, the EXPLAIN
output for the new tests shows more partitions being accessed than
seem strictly necessary to satisfy the queries being explained.

For the curious:

      query condition      =>   partition with matching data
      ---------------           ----------------------------
WHERE beta.a = 'äbç'       =>           beta_f
WHERE beta.a = 'ὀδυσσεύς'  =>           beta_default
WHERE alpha.a = 'äbç'      =>           alpha_e
WHERE alpha.a = 'ὀδυσσεύς' =>           alpha_default

Both tables alpha and beta have other partitions which contain
neither of these two strings.

When joining alpha with beta with the restriction

     alpha.a = beta.a and alpha.a = 'äbç'

the planner accesses all four of beta_f, beta_default, alpha_e,
and alpha_default, despite not needing anything from the default
partitions.  Interestingly, when querying with the restriction

     alpha.a = beta.a and alpha.a = 'ὀδυσσεύς'

the planner does the right thing and only checks the default
partitions.

When joining with

    alpha.a = beta.a and alpha.a IN ('äbç', 'ὀδυσσεύς')

the planner does the right thing for one side of the query, but
hits all partitions for the other side, which it doesn't need to
do.

The queries return the right results, so these critiques are
restricted to performance and not correctness.
---
 src/test/regress/expected/partition_join.out | 407 +++++++++++++++++++
 src/test/regress/sql/partition_join.sql      | 110 +++++
 2 files changed, 517 insertions(+)

diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 924cb99863..f20a85689f 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -4168,3 +4168,410 @@ SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM (plt1_ad t1 LEFT JOIN plt2_ad t2
  22 | 0002 | 22 | 0002 |    | 
 (55 rows)
 
+CREATE TABLE raw_data (a text);
+INSERT INTO raw_data (a) VALUES ('Türkiye'),
+								('TÜRKIYE'),
+								('bıt'),
+								('BIT'),
+								('äbç'),
+								('ÄBÇ'),
+								('aaá'),
+								('coté'),
+								('Götz'),
+								('ὀδυσσεύς'),
+								('ὈΔΥΣΣΕΎΣ'),
+								('を読み取り用'),
+								('にオープンできませんでした');
+CREATE TABLE alpha
+	(a TEXT, b TEXT)
+	PARTITION BY RANGE(a, b);
+CREATE TABLE alpha_a PARTITION OF alpha FOR VALUES FROM ('a','v') TO ('c','q');
+CREATE TABLE alpha_b PARTITION OF alpha FOR VALUES FROM ('c','q') TO ('d','f');
+CREATE TABLE alpha_c PARTITION OF alpha FOR VALUES FROM ('d','f') TO ('p','m');
+CREATE TABLE alpha_d PARTITION OF alpha FOR VALUES FROM ('p','m') TO ('z','z');
+CREATE TABLE alpha_e PARTITION OF alpha FOR VALUES FROM ('z','z') TO ('√','Σ');
+CREATE TABLE alpha_f PARTITION OF alpha FOR VALUES FROM ('√','Σ') TO ('き','ま');
+CREATE TABLE alpha_default PARTITION OF alpha DEFAULT;
+CREATE TABLE beta
+	(a TEXT, b TEXT)
+	PARTITION BY RANGE(a, b);
+CREATE TABLE beta_a PARTITION OF beta FOR VALUES FROM ('a','z') TO ('d','z');
+CREATE TABLE beta_b PARTITION OF beta FOR VALUES FROM ('d','z') TO ('g','z');
+CREATE TABLE beta_c PARTITION OF beta FOR VALUES FROM ('g','z') TO ('k','z');
+CREATE TABLE beta_d PARTITION OF beta FOR VALUES FROM ('k','z') TO ('o','z');
+CREATE TABLE beta_e PARTITION OF beta FOR VALUES FROM ('o','z') TO ('t','z');
+CREATE TABLE beta_f PARTITION OF beta FOR VALUES FROM ('t','z') TO ('Δ','υ');
+CREATE TABLE beta_g PARTITION OF beta FOR VALUES FROM ('Δ','υ') TO ('ὀ','√');
+CREATE TABLE beta_h PARTITION OF beta FOR VALUES FROM ('ὀ','√') TO ('ん', '用');
+CREATE TABLE beta_default PARTITION OF beta DEFAULT;
+INSERT INTO alpha (SELECT a, a FROM raw_data);
+INSERT INTO beta (SELECT a, a FROM raw_data);
+ANALYZE alpha;
+ANALYZE beta;
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Hash Join
+   Hash Cond: (t2.a = t1.a)
+   ->  Append
+         ->  Seq Scan on beta_a t2_1
+         ->  Seq Scan on beta_b t2_2
+         ->  Seq Scan on beta_c t2_3
+         ->  Seq Scan on beta_d t2_4
+         ->  Seq Scan on beta_e t2_5
+         ->  Seq Scan on beta_f t2_6
+         ->  Seq Scan on beta_g t2_7
+         ->  Seq Scan on beta_h t2_8
+         ->  Seq Scan on beta_default t2_9
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on alpha_e t1_1
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+               ->  Seq Scan on alpha_default t1_2
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+(18 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+    a     |    a     
+----------+----------
+ äbç      | äbç
+ ὀδυσσεύς | ὀδυσσεύς
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Nested Loop
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = 'äbç'::text)
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = 'äbç'::text)
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on beta_f t2_1
+                     Filter: (a = 'äbç'::text)
+               ->  Seq Scan on beta_default t2_2
+                     Filter: (a = 'äbç'::text)
+(12 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+  a  |  a  
+-----+-----
+ äbç | äbç
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+               QUERY PLAN               
+----------------------------------------
+ Nested Loop
+   ->  Seq Scan on alpha_default t1
+         Filter: (a = 'ὀδυσσεύς'::text)
+   ->  Seq Scan on beta_default t2
+         Filter: (a = 'ὀδυσσεύς'::text)
+(5 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+    a     |    a     
+----------+----------
+ ὀδυσσεύς | ὀδυσσεύς
+(1 row)
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Hash Semi Join
+   Hash Cond: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on beta_a t2_1
+               ->  Seq Scan on beta_b t2_2
+               ->  Seq Scan on beta_c t2_3
+               ->  Seq Scan on beta_d t2_4
+               ->  Seq Scan on beta_e t2_5
+               ->  Seq Scan on beta_f t2_6
+               ->  Seq Scan on beta_g t2_7
+               ->  Seq Scan on beta_h t2_8
+               ->  Seq Scan on beta_default t2_9
+(18 rows)
+
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+    a     
+----------
+ äbç
+ ὀδυσσεύς
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Nested Loop Semi Join
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = 'äbç'::text)
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = 'äbç'::text)
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on beta_f t2_1
+                     Filter: (a = 'äbç'::text)
+               ->  Seq Scan on beta_default t2_2
+                     Filter: (a = 'äbç'::text)
+(12 rows)
+
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+  a  
+-----
+ äbç
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+               QUERY PLAN               
+----------------------------------------
+ Nested Loop Semi Join
+   ->  Seq Scan on alpha_default t1
+         Filter: (a = 'ὀδυσσεύς'::text)
+   ->  Seq Scan on beta_default t2
+         Filter: (a = 'ὀδυσσεύς'::text)
+(5 rows)
+
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+    a     
+----------
+ ὀδυσσεύς
+(1 row)
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Hash Right Join
+   Hash Cond: (t2.a = t1.a)
+   ->  Append
+         ->  Seq Scan on beta_a t2_1
+         ->  Seq Scan on beta_b t2_2
+         ->  Seq Scan on beta_c t2_3
+         ->  Seq Scan on beta_d t2_4
+         ->  Seq Scan on beta_e t2_5
+         ->  Seq Scan on beta_f t2_6
+         ->  Seq Scan on beta_g t2_7
+         ->  Seq Scan on beta_h t2_8
+         ->  Seq Scan on beta_default t2_9
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on alpha_e t1_1
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+               ->  Seq Scan on alpha_default t1_2
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+(18 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+    a     |    a     
+----------+----------
+ äbç      | äbç
+ ὀδυσσεύς | ὀδυσσεύς
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Nested Loop Left Join
+   Join Filter: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = 'äbç'::text)
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = 'äbç'::text)
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on beta_f t2_1
+                     Filter: (a = 'äbç'::text)
+               ->  Seq Scan on beta_default t2_2
+                     Filter: (a = 'äbç'::text)
+(13 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+  a  |  a  
+-----+-----
+ äbç | äbç
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+               QUERY PLAN               
+----------------------------------------
+ Nested Loop Left Join
+   Join Filter: (t1.a = t2.a)
+   ->  Seq Scan on alpha_default t1
+         Filter: (a = 'ὀδυσσεύς'::text)
+   ->  Seq Scan on beta_default t2
+         Filter: (a = 'ὀδυσσεύς'::text)
+(6 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+    a     |    a     
+----------+----------
+ ὀδυσσεύς | ὀδυσσεύς
+(1 row)
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Hash Anti Join
+   Hash Cond: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on beta_a t2_1
+               ->  Seq Scan on beta_b t2_2
+               ->  Seq Scan on beta_c t2_3
+               ->  Seq Scan on beta_d t2_4
+               ->  Seq Scan on beta_e t2_5
+               ->  Seq Scan on beta_f t2_6
+               ->  Seq Scan on beta_g t2_7
+               ->  Seq Scan on beta_h t2_8
+               ->  Seq Scan on beta_default t2_9
+(18 rows)
+
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+ a 
+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Nested Loop Anti Join
+   Join Filter: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = 'äbç'::text)
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = 'äbç'::text)
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on beta_f t2_1
+                     Filter: (a = 'äbç'::text)
+               ->  Seq Scan on beta_default t2_2
+                     Filter: (a = 'äbç'::text)
+(13 rows)
+
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+ a 
+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+               QUERY PLAN               
+----------------------------------------
+ Nested Loop Anti Join
+   Join Filter: (t1.a = t2.a)
+   ->  Seq Scan on alpha_default t1
+         Filter: (a = 'ὀδυσσεύς'::text)
+   ->  Seq Scan on beta_default t2
+         Filter: (a = 'ὀδυσσεύς'::text)
+(6 rows)
+
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+ a 
+---
+(0 rows)
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Hash Right Join
+   Hash Cond: (t2.a = t1.a)
+   ->  Append
+         ->  Seq Scan on beta_a t2_1
+         ->  Seq Scan on beta_b t2_2
+         ->  Seq Scan on beta_c t2_3
+         ->  Seq Scan on beta_d t2_4
+         ->  Seq Scan on beta_e t2_5
+         ->  Seq Scan on beta_f t2_6
+         ->  Seq Scan on beta_g t2_7
+         ->  Seq Scan on beta_h t2_8
+         ->  Seq Scan on beta_default t2_9
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on alpha_e t1_1
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+               ->  Seq Scan on alpha_default t1_2
+                     Filter: (a = ANY ('{äbç,ὀδυσσεύς}'::text[]))
+(18 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+    a     |    a     
+----------+----------
+ äbç      | äbç
+ ὀδυσσεύς | ὀδυσσεύς
+(2 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Nested Loop Left Join
+   Join Filter: (t1.a = t2.a)
+   ->  Append
+         ->  Seq Scan on alpha_e t1_1
+               Filter: (a = 'äbç'::text)
+         ->  Seq Scan on alpha_default t1_2
+               Filter: (a = 'äbç'::text)
+   ->  Materialize
+         ->  Append
+               ->  Seq Scan on beta_f t2_1
+                     Filter: (a = 'äbç'::text)
+               ->  Seq Scan on beta_default t2_2
+                     Filter: (a = 'äbç'::text)
+(13 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+  a  |  a  
+-----+-----
+ äbç | äbç
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+               QUERY PLAN               
+----------------------------------------
+ Nested Loop Left Join
+   Join Filter: (t1.a = t2.a)
+   ->  Seq Scan on alpha_default t1
+         Filter: (a = 'ὀδυσσεύς'::text)
+   ->  Seq Scan on beta_default t2
+         Filter: (a = 'ὀδυσσεύς'::text)
+(6 rows)
+
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+    a     |    a     
+----------+----------
+ ὀδυσσεύς | ὀδυσσεύς
+(1 row)
+
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index 418ffa117f..159d459831 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -954,3 +954,113 @@ ANALYZE plt3_ad;
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM (plt1_ad t1 LEFT JOIN plt2_ad t2 ON (t1.c = t2.c)) FULL JOIN plt3_ad 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;
 SELECT t1.a, t1.c, t2.a, t2.c, t3.a, t3.c FROM (plt1_ad t1 LEFT JOIN plt2_ad t2 ON (t1.c = t2.c)) FULL JOIN plt3_ad 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;
+
+CREATE TABLE raw_data (a text);
+INSERT INTO raw_data (a) VALUES ('Türkiye'),
+								('TÜRKIYE'),
+								('bıt'),
+								('BIT'),
+								('äbç'),
+								('ÄBÇ'),
+								('aaá'),
+								('coté'),
+								('Götz'),
+								('ὀδυσσεύς'),
+								('ὈΔΥΣΣΕΎΣ'),
+								('を読み取り用'),
+								('にオープンできませんでした');
+
+CREATE TABLE alpha
+	(a TEXT, b TEXT)
+	PARTITION BY RANGE(a, b);
+CREATE TABLE alpha_a PARTITION OF alpha FOR VALUES FROM ('a','v') TO ('c','q');
+CREATE TABLE alpha_b PARTITION OF alpha FOR VALUES FROM ('c','q') TO ('d','f');
+CREATE TABLE alpha_c PARTITION OF alpha FOR VALUES FROM ('d','f') TO ('p','m');
+CREATE TABLE alpha_d PARTITION OF alpha FOR VALUES FROM ('p','m') TO ('z','z');
+CREATE TABLE alpha_e PARTITION OF alpha FOR VALUES FROM ('z','z') TO ('√','Σ');
+CREATE TABLE alpha_f PARTITION OF alpha FOR VALUES FROM ('√','Σ') TO ('き','ま');
+CREATE TABLE alpha_default PARTITION OF alpha DEFAULT;
+
+CREATE TABLE beta
+	(a TEXT, b TEXT)
+	PARTITION BY RANGE(a, b);
+CREATE TABLE beta_a PARTITION OF beta FOR VALUES FROM ('a','z') TO ('d','z');
+CREATE TABLE beta_b PARTITION OF beta FOR VALUES FROM ('d','z') TO ('g','z');
+CREATE TABLE beta_c PARTITION OF beta FOR VALUES FROM ('g','z') TO ('k','z');
+CREATE TABLE beta_d PARTITION OF beta FOR VALUES FROM ('k','z') TO ('o','z');
+CREATE TABLE beta_e PARTITION OF beta FOR VALUES FROM ('o','z') TO ('t','z');
+CREATE TABLE beta_f PARTITION OF beta FOR VALUES FROM ('t','z') TO ('Δ','υ');
+CREATE TABLE beta_g PARTITION OF beta FOR VALUES FROM ('Δ','υ') TO ('ὀ','√');
+CREATE TABLE beta_h PARTITION OF beta FOR VALUES FROM ('ὀ','√') TO ('ん', '用');
+CREATE TABLE beta_default PARTITION OF beta DEFAULT;
+
+INSERT INTO alpha (SELECT a, a FROM raw_data);
+INSERT INTO beta (SELECT a, a FROM raw_data);
+
+ANALYZE alpha;
+ANALYZE beta;
+
+-- inner join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+SELECT t1.a, t2.a FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+
+-- semi join
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+SELECT t1.a FROM alpha t1 WHERE EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+
+-- left join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+SELECT t1.a, t2.a FROM alpha t1 LEFT JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+
+-- anti join
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a IN ('äbç', 'ὀδυσσεύς');
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'äbç';
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+SELECT t1.a FROM alpha t1 WHERE NOT EXISTS (SELECT 1 FROM beta t2 WHERE t1.a = t2.a) AND t1.a = 'ὀδυσσεύς';
+
+-- full join
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a IN ('äbç', 'ὀδυσσεύς');
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'äbç';
+
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
+SELECT t1.a, t2.a FROM alpha t1 FULL JOIN beta t2 ON (t1.a = t2.a) WHERE t1.a = 'ὀδυσσεύς';
-- 
2.21.1 (Apple Git-122.3)

