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); + } }
