calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject incubator-calcite git commit: [CALCITE-554] Outer join over NULL keys generates wrong result
Date Thu, 08 Jan 2015 04:35:32 GMT
Repository: incubator-calcite
Updated Branches:
  refs/heads/master f2df8e7c4 -> 1edcba060


[CALCITE-554] Outer join over NULL keys generates wrong result


Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/1edcba06
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/1edcba06
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/1edcba06

Branch: refs/heads/master
Commit: 1edcba060a55888204f32b8516eee65f8409c8e7
Parents: f2df8e7
Author: Julian Hyde <jhyde@apache.org>
Authored: Wed Jan 7 20:16:00 2015 -0800
Committer: Julian Hyde <jhyde@apache.org>
Committed: Wed Jan 7 20:16:00 2015 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/test/JdbcTest.java  |  1 +
 core/src/test/resources/sql/outer.oq            | 78 +++++++++++++++++++-
 .../calcite/linq4j/EnumerableDefaults.java      | 56 +++++++-------
 .../apache/calcite/linq4j/test/Linq4jTest.java  |  3 +-
 4 files changed, 111 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1edcba06/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index add91fa..8d45b6c 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -4248,6 +4248,7 @@ public class JdbcTest {
             "deptno=10; deptno=10",
             "deptno=10; deptno=10",
             "deptno=20; deptno=null",
+            "deptno=null; deptno=null",
             "deptno=null; deptno=30",
             "deptno=null; deptno=40");
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1edcba06/core/src/test/resources/sql/outer.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/outer.oq b/core/src/test/resources/sql/outer.oq
index fe94a70..0355f64 100644
--- a/core/src/test/resources/sql/outer.oq
+++ b/core/src/test/resources/sql/outer.oq
@@ -223,8 +223,9 @@ select * from (select * from emp where gender ='F') as emp full join dept
on emp
 | Wilma |        | F      |         |             |
 |       |        |        |      20 | Marketing   |
 |       |        |        |      40 | Empty       |
+|       |        |        |         |             |
 +-------+--------+--------+---------+-------------+
-(8 rows)
+(9 rows)
 
 !ok
 
@@ -269,5 +270,80 @@ EnumerableThetaJoin(condition=[=(-($1, $3), 0)], joinType=[full])
   EnumerableValues(tuples=[[{ 10, 'Sales      ' }, { 20, 'Marketing  ' }, { 30, 'Engineering'
}, { 40, 'Empty      ' }]])
 !plan
 
+# [CALCITE-554] Outer join over NULL keys generates wrong result
+with t1(x) as (select * from  (values (1),(2), (case when 1 = 1 then null else 3 end)) as
t(x)),
+  t2(x) as (select * from  (values (1),(case when 1 = 1 then null else 3 end)) as t(x))
+select t1.x from t1 left join t2 on t1.x = t2.x;
++---+
+| X |
++---+
+| 1 |
+| 2 |
+|   |
++---+
+(3 rows)
+
+!ok
+
+# Equivalent query, using CAST, and skipping unnecessary aliases
+with t1(x) as (select * from (values 1, 2, cast(null as integer))),
+  t2(x) as (select * from (values 1, cast(null as integer)))
+select t1.x from t1 left join t2 on t1.x = t2.x;
++---+
+| X |
++---+
+| 1 |
+| 2 |
+|   |
++---+
+(3 rows)
+
+!ok
+
+# Similar query, projecting both columns
+with t1(x) as (select * from (values 1, 2, cast(null as integer))),
+  t2(x) as (select * from (values 1, cast(null as integer)))
+select t1.x, t2.x from t1 left join t2 on t1.x = t2.x;
++---+---+
+| X | X |
++---+---+
+| 1 | 1 |
+| 2 |   |
+|   |   |
++---+---+
+(3 rows)
+
+!ok
+
+# Similar, with 2 columns on each side projecting both columns
+with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer), 30))),
+  t2(x, y) as (select * from (values (1, 100), (cast(null as integer), 200)))
+select * from t1 left join t2 on t1.x = t2.x;
++---+----+----+-----+
+| X | Y  | X0 | Y0  |
++---+----+----+-----+
+| 1 | 10 |  1 | 100 |
+| 2 | 20 |    |     |
+|   | 30 |    | 200 |
++---+----+----+-----+
+(3 rows)
+
+!ok
+
+# Similar, full join
+with t1(x, y) as (select * from (values (1, 10), (2, 20), (cast(null as integer), 30))),
+  t2(x, y) as (select * from (values (1,100), (cast(null as integer), 200)))
+select * from t1 full join t2 on t1.x = t2.x;
++---+----+----+-----+
+| X | Y  | X0 | Y0  |
++---+----+----+-----+
+| 1 | 10 |  1 | 100 |
+| 2 | 20 |    |     |
+|   | 30 |    | 200 |
+|   |    |    |     |
++---+----+----+-----+
+(4 rows)
+
+!ok
 
 # End outer.oq

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1edcba06/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
index 4be759c..f0d68d8 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/EnumerableDefaults.java
@@ -998,15 +998,16 @@ public abstract class EnumerableDefaults {
                 return false;
               }
               final TSource outer = outers.current();
+              final Enumerable<TInner> innerEnumerable;
               if (outer == null) {
-                continue;
-              }
-              final TKey outerKey = outerKeySelector.apply(outer);
-              if (unmatchedKeys != null) {
-                unmatchedKeys.remove(outerKey);
+                innerEnumerable = null;
+              } else {
+                final TKey outerKey = outerKeySelector.apply(outer);
+                if (unmatchedKeys != null) {
+                  unmatchedKeys.remove(outerKey);
+                }
+                innerEnumerable = innerLookup.get(outerKey);
               }
-              final Enumerable<TInner> innerEnumerable =
-                  innerLookup.get(outerKey);
               if (innerEnumerable == null
                   || !innerEnumerable.any()) {
                 if (generateNullsOnRight) {
@@ -1526,15 +1527,16 @@ public abstract class EnumerableDefaults {
       Enumerable<TSource> source) {
     final List<TSource> list = toList(source);
     final int n = list.size();
-    return Linq4j.asEnumerable(new AbstractList<TSource>() {
-      public TSource get(int index) {
-        return list.get(n - 1 - index);
-      }
+    return Linq4j.asEnumerable(
+        new AbstractList<TSource>() {
+          public TSource get(int index) {
+            return list.get(n - 1 - index);
+          }
 
-      public int size() {
-        return n;
-      }
-    });
+          public int size() {
+            return n;
+          }
+        });
   }
 
   /**
@@ -1903,12 +1905,13 @@ public abstract class EnumerableDefaults {
    */
   public static <TSource> Enumerable<TSource> take(Enumerable<TSource>
source,
       final int count) {
-    return takeWhile(source, new Predicate2<TSource, Integer>() {
-      public boolean apply(TSource v1, Integer v2) {
-        // Count is 1-based
-        return v2 < count;
-      }
-    });
+    return takeWhile(
+        source, new Predicate2<TSource, Integer>() {
+          public boolean apply(TSource v1, Integer v2) {
+            // Count is 1-based
+            return v2 < count;
+          }
+        });
   }
 
   /**
@@ -2080,8 +2083,8 @@ public abstract class EnumerableDefaults {
   public static <TSource, TKey> Lookup<TKey, TSource> toLookup(
       Enumerable<TSource> source, Function1<TSource, TKey> keySelector,
       EqualityComparer<TKey> comparer) {
-    return toLookup(source, keySelector, Functions.<TSource>identitySelector(),
-        comparer);
+    return toLookup(
+        source, keySelector, Functions.<TSource>identitySelector(), comparer);
   }
 
   /**
@@ -2135,8 +2138,11 @@ public abstract class EnumerableDefaults {
       Enumerable<TSource> source, Function1<TSource, TKey> keySelector,
       Function1<TSource, TElement> elementSelector,
       EqualityComparer<TKey> comparer) {
-    return toLookup_(new WrapMap<TKey, List<TElement>>(comparer), source,
-        keySelector, elementSelector);
+    return toLookup_(
+        new WrapMap<TKey, List<TElement>>(comparer),
+        source,
+        keySelector,
+        elementSelector);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1edcba06/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
index 4e133c1..216aaff 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
@@ -973,7 +973,8 @@ public class Linq4jTest {
             + "Eric works in Sales, "
             + "Fred works in Sales, "
             + "Janet works in Sales, "
-            + "null works in HR]",
+            + "null works in HR, "
+            + "null works in null]",
         s);
   }
 


Mime
View raw message