TAJO-880: NULL in CASE clause occurs Exception. (Hyoungjun Kim via hyunsik)

 Closes #40


Project: http://git-wip-us.apache.org/repos/asf/tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/4ec8f0dd
Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/4ec8f0dd
Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/4ec8f0dd

Branch: refs/heads/window_function
Commit: 4ec8f0dd44fb58279c00e896a1aebefc40bd8017
Parents: 9f54c4b
Author: Hyunsik Choi <[email protected]>
Authored: Fri Jun 20 14:24:42 2014 +0900
Committer: Hyunsik Choi <[email protected]>
Committed: Fri Jun 20 14:24:42 2014 +0900

----------------------------------------------------------------------
 CHANGES                                         |  2 +
 .../java/org/apache/tajo/datum/NullDatum.java   |  7 +++
 .../apache/tajo/engine/eval/CaseWhenEval.java   | 14 ++++-
 .../tajo/engine/planner/ExprAnnotator.java      | 14 ++++-
 .../tajo/engine/query/TestCaseByCases.java      | 66 ++++++++++++++++++++
 5 files changed, 99 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/4ec8f0dd/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 3cdebae..636808d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -71,6 +71,8 @@ Release 0.9.0 - unreleased
 
   BUG FIXES
 
+    TAJO-880: NULL in CASE clause occurs Exception. (Hyoungjun Kim via hyunsik)
+
     TAJO-862: Restore failure of dumped relations. (jihoon)
 
     TAJO-861: tajo-dump script are not executable. (jinho)

http://git-wip-us.apache.org/repos/asf/tajo/blob/4ec8f0dd/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java 
b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
index 9842490..a4f79d7 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
@@ -18,6 +18,7 @@
 
 package org.apache.tajo.datum;
 
+import org.apache.tajo.common.TajoDataTypes.DataType;
 import org.apache.tajo.exception.InvalidCastException;
 
 import static org.apache.tajo.common.TajoDataTypes.Type;
@@ -25,9 +26,11 @@ import static org.apache.tajo.common.TajoDataTypes.Type;
 public class NullDatum extends Datum {
   private static NullDatum instance;
   private static final byte [] EMPTY_BYTES = new byte[0];
+  private static final DataType NULL_DATA_TYPE;
 
   static {
     instance = new NullDatum();
+    NULL_DATA_TYPE = DataType.newBuilder().setType(Type.NULL_TYPE).build();
   }
 
   private NullDatum() {
@@ -38,6 +41,10 @@ public class NullDatum extends Datum {
     return instance;
   }
 
+  public static DataType getDataType() {
+    return NULL_DATA_TYPE;
+  }
+
   @Override
   public boolean isNull() {
     return true;

http://git-wip-us.apache.org/repos/asf/tajo/blob/4ec8f0dd/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git 
a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java 
b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
index 6b330f5..85b5bc0 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -24,6 +24,7 @@ import org.apache.tajo.catalog.CatalogUtil;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.common.TajoDataTypes;
 import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.common.TajoDataTypes.Type;
 import org.apache.tajo.datum.Datum;
 import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.json.CoreGsonHelper;
@@ -64,7 +65,18 @@ public class CaseWhenEval extends EvalNode implements 
GsonObject {
 
   @Override
   public DataType getValueType() {
-    return whens.get(0).getResult().getValueType();
+    // Find not null type
+    for (IfThenEval eachWhen: whens) {
+      if (eachWhen.getResult().getValueType().getType() != Type.NULL_TYPE) {
+        return eachWhen.getResult().getValueType();
+      }
+    }
+
+    if (elseResult != null) { // without else clause
+      return elseResult.getValueType();
+    }
+
+    return NullDatum.getDataType();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/tajo/blob/4ec8f0dd/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
----------------------------------------------------------------------
diff --git 
a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java 
b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
index e799e30..3a53cd2 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
@@ -125,9 +125,17 @@ public class ExprAnnotator extends 
BaseAlgebraVisitor<ExprAnnotator.Context, Eva
   static DataType getWidestType(DataType...types) throws PlanningException {
     DataType widest = types[0];
     for (int i = 1; i < types.length; i++) {
-      Type candidate = TUtil.getFromNestedMap(TYPE_CONVERSION_MAP, 
widest.getType(), types[i].getType());
-      assertEval(candidate != null, "No matched operation for those types: " + 
TUtil.arrayToString(types));
-      widest = CatalogUtil.newSimpleDataType(candidate);
+
+      if (widest.getType() == Type.NULL_TYPE) { // if null, skip this type
+        widest = types[i];
+        continue;
+      }
+
+      if (types[i].getType() != Type.NULL_TYPE) {
+        Type candidate = TUtil.getFromNestedMap(TYPE_CONVERSION_MAP, 
widest.getType(), types[i].getType());
+        assertEval(candidate != null, "No matched operation for those types: " 
+ TUtil.arrayToString(types));
+        widest = CatalogUtil.newSimpleDataType(candidate);
+      }
     }
 
     return widest;

http://git-wip-us.apache.org/repos/asf/tajo/blob/4ec8f0dd/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCaseByCases.java
----------------------------------------------------------------------
diff --git 
a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCaseByCases.java 
b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCaseByCases.java
index 9836a57..73df4e1 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCaseByCases.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCaseByCases.java
@@ -24,6 +24,8 @@ import org.junit.Test;
 
 import java.sql.ResultSet;
 
+import static org.junit.Assert.assertEquals;
+
 public class TestCaseByCases extends QueryTestCaseBase {
 
   public TestCaseByCases() {
@@ -67,4 +69,68 @@ public class TestCaseByCases extends QueryTestCaseBase {
     assertResultSet(res);
     cleanupQuery(res);
   }
+
+  @Test
+  public final void testTAJO880_1() throws Exception {
+    //TAJO-880: NULL in CASE clause occurs Exception.
+    ResultSet res = executeString(
+        "select case when l_returnflag != 'R' then l_orderkey else null end 
from lineitem"
+    );
+
+    String expected =
+        "?casewhen\n" +
+        "-------------------------------\n" +
+        "1\n" +
+        "1\n" +
+        "2\n" +
+        "null\n" +
+        "null\n";
+
+    assertEquals(expected, resultSetToString(res));
+    cleanupQuery(res);
+  }
+
+  @Test
+  public final void testTAJO880_2() throws Exception {
+    //TAJO-880: NULL in CASE clause occurs Exception.
+    ResultSet res = executeString(
+        "select case when l_returnflag != 'R' then null else l_orderkey end 
from lineitem"
+    );
+
+    String expected =
+        "?casewhen\n" +
+        "-------------------------------\n" +
+        "null\n" +
+        "null\n" +
+        "null\n" +
+        "3\n" +
+        "3\n";
+
+    assertEquals(expected, resultSetToString(res));
+    cleanupQuery(res);
+  }
+
+  @Test
+  public final void testTAJO880_3() throws Exception {
+    //TAJO-880: NULL in CASE clause occurs Exception.
+    ResultSet res = executeString(
+        "select case " +
+            "when l_orderkey = 1 then null " +
+            "when l_orderkey = 2 then l_orderkey " +
+            "else null end " +
+        "from lineitem"
+    );
+
+    String expected =
+        "?casewhen\n" +
+            "-------------------------------\n" +
+            "null\n" +
+            "null\n" +
+            "2\n" +
+            "null\n" +
+            "null\n";
+
+    assertEquals(expected, resultSetToString(res));
+    cleanupQuery(res);
+  }
 }

Reply via email to