v30-0002-Fix-handling-of-NULL-partitions.patch

application/octet-stream

Filename: v30-0002-Fix-handling-of-NULL-partitions.patch
Type: application/octet-stream
Part: 1
Message: Re: [HACKERS] advanced partition matching algorithm for partition-wise join

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v30-0002
File+
src/backend/partitioning/partbounds.c 12 14
src/test/regress/expected/partition_join.out 70 0
src/test/regress/sql/partition_join.sql 9 0
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index d619ab4486..0c1e4ab7f5 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -4528,8 +4528,8 @@ merge_null_partitions(PartitionMap *outer_map,
 					  int *next_index,
 					  int *null_index)
 {
-	bool 		merge_outer_null = false;
-	bool 		merge_inner_null = false;
+	bool 		outer_null_unmerged = false;
+	bool 		inner_null_unmerged = false;
 
 	Assert(outer_has_null || inner_has_null);
 	Assert(*null_index == -1);
@@ -4554,7 +4554,7 @@ merge_null_partitions(PartitionMap *outer_map,
 		 */
 		Assert(outer_null >= 0 && outer_null < outer_map->nparts);
 		if (outer_map->merged_indexes[outer_null] == -1)
-			merge_outer_null = true;
+		 	outer_null_unmerged = true;
 	}
 	if (inner_has_null)
 	{
@@ -4565,15 +4565,14 @@ merge_null_partitions(PartitionMap *outer_map,
 		 * partition below.
 		 */
 		Assert(inner_null >= 0 && inner_null < inner_map->nparts);
-		if (jointype == JOIN_FULL &&
-			inner_map->merged_indexes[inner_null] == -1)
-			merge_inner_null = true;
+		if (inner_map->merged_indexes[inner_null] == -1)
+			inner_null_unmerged = true;
 	}
 
-	if (!merge_outer_null && !merge_inner_null)
+	if (!outer_null_unmerged && !inner_null_unmerged)
 		return;
 
-	if (merge_outer_null && !merge_inner_null)
+	if (outer_null_unmerged && !inner_null_unmerged)
 	{
 		Assert(outer_has_null);
 
@@ -4584,24 +4583,23 @@ merge_null_partitions(PartitionMap *outer_map,
 		*null_index = merge_partition_with_dummy(outer_map, outer_null,
 												 next_index);
 	}
-	else if (!merge_outer_null && merge_inner_null)
+	else if (!outer_null_unmerged && inner_null_unmerged)
 	{
 		Assert(inner_has_null);
-		Assert(jointype == JOIN_FULL);
 
 		/*
 		 * Assign a new merged partition.  The resulting partition should be
 		 * the NULL partition of the joinrel.
 		 */
-		*null_index = merge_partition_with_dummy(inner_map, inner_null,
-												 next_index);
+		if (jointype == JOIN_FULL)
+			*null_index = merge_partition_with_dummy(inner_map, inner_null,
+													 next_index);
 	}
 	else
 	{
-		Assert(merge_outer_null && merge_inner_null);
+		Assert(outer_null_unmerged && inner_null_unmerged);
 		Assert(outer_has_null);
 		Assert(inner_has_null);
-		Assert(jointype == JOIN_FULL);
 
 		/*
 		 * Merge the NULL partitions.  Both partitions aren't merged yet, so
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index dc78bc2503..924cb99863 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -3673,6 +3673,32 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t
  9 | 0009 | 9 | 0009
 (4 rows)
 
+-- Partitioned join can't be applied because there isn't any partition on the
+-- plt2_ad side that matches the NULL partition of plt1_ad plt1_ad_extra
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad 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_ad_p1 t2_1
+               ->  Seq Scan on plt2_ad_p2 t2_2
+               ->  Seq Scan on plt2_ad_p3 t2_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on plt1_ad_p1 t1_1
+                           Filter: (b < 10)
+                     ->  Seq Scan on plt1_ad_p2 t1_2
+                           Filter: (b < 10)
+                     ->  Seq Scan on plt1_ad_p3 t1_3
+                           Filter: (b < 10)
+                     ->  Seq Scan on plt1_ad_extra t1_4
+                           Filter: (b < 10)
+(18 rows)
+
 -- Partitioned join can't be applied because there isn't any partition on the
 -- plt2_ad side that matches the NULL partition of plt1_ad plt1_ad_extra
 EXPLAIN (COSTS OFF)
@@ -3737,6 +3763,50 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t
  9 | 0009 | 9 | 0009
 (4 rows)
 
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad 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_ad_p1 t2_1
+               ->  Hash
+                     ->  Seq Scan on plt1_ad_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_ad_p2 t2_2
+               ->  Hash
+                     ->  Seq Scan on plt1_ad_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_ad_p3 t2_3
+               ->  Hash
+                     ->  Seq Scan on plt1_ad_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_ad_extra t1_4
+                     Filter: (b < 10)
+               ->  Seq Scan on plt2_ad_extra t2_4
+(26 rows)
+
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad 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)
+
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 FULL JOIN plt2_ad 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                                     
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index c3e47ee549..418ffa117f 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -815,6 +815,11 @@ EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
 
+-- Partitioned join can't be applied because there isn't any partition on the
+-- plt2_ad side that matches the NULL partition of plt1_ad plt1_ad_extra
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+
 -- Partitioned join can't be applied because there isn't any partition on the
 -- plt2_ad side that matches the NULL partition of plt1_ad plt1_ad_extra
 EXPLAIN (COSTS OFF)
@@ -830,6 +835,10 @@ EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 INNER JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
 
+EXPLAIN (COSTS OFF)
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 LEFT JOIN plt2_ad t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE t1.b < 10 ORDER BY t1.a;
+
 EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 FULL JOIN plt2_ad 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;
 SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_ad t1 FULL JOIN plt2_ad 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;