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;