Repository: tajo
Updated Branches:
  refs/heads/branch-0.11.2 3e083b164 -> e65f4a2b4


TAJO-2089: Improve null handling in UDF.


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

Branch: refs/heads/branch-0.11.2
Commit: e65f4a2b406210bd25daf8e2f68b5d332b2eec45
Parents: 3e083b1
Author: Jinho Kim <[email protected]>
Authored: Tue Mar 8 16:14:38 2016 +0900
Committer: Jinho Kim <[email protected]>
Committed: Tue Mar 8 16:14:38 2016 +0900

----------------------------------------------------------------------
 CHANGES                                         |  4 ++
 .../apache/tajo/exception/ErrorMessages.java    | 12 ++++--
 .../engine/codegen/TestEvalCodeGenerator.java   | 13 +++---
 .../apache/tajo/engine/eval/ExprTestBase.java   |  2 +-
 .../tajo/engine/function/NullTestFunction.java  | 45 ++++++++++++++++++++
 .../function/TestConditionalExpressions.java    | 13 +++---
 .../tajo/engine/function/TestJsonFunctions.java |  7 +--
 .../tajo/engine/function/TestMathFunctions.java |  7 +--
 .../function/TestPatternMatchingPredicates.java |  5 ++-
 .../TestStringOperatorsAndFunctions.java        | 13 +++---
 .../function/TestUserDefinedFunctions.java      | 43 +++++++++++++++++++
 .../org/apache/tajo/master/QueryInProgress.java |  2 +-
 .../tajo/plan/expr/GeneralFunctionEval.java     |  8 +++-
 13 files changed, 142 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 1095644..3f44ff7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@ Tajo Change Log
 
 Release 0.11.2 - unreleased
 
+  IMPROVEMENT
+
+    TAJO-2089: Improve null handling in UDF. (jinho)
+
   TASKS
 
     TAJO-2088: Change QueryTestCaseBase.runSimpleTests() to return a set of 

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java
----------------------------------------------------------------------
diff --git 
a/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java 
b/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java
index ffb5eb3..f2cdac3 100644
--- a/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java
+++ b/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java
@@ -19,8 +19,10 @@
 package org.apache.tajo.exception;
 
 import com.google.common.collect.Maps;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.tajo.error.Errors.ResultCode;
 import org.apache.tajo.util.Pair;
+import org.apache.tajo.util.StringUtils;
 
 import java.util.Map;
 
@@ -137,12 +139,16 @@ public class ErrorMessages {
   }
 
   public static String getInternalErrorMessage(Throwable t) {
-    if (t.getMessage() != null) {
-      return String.format(MESSAGES.get(INTERNAL_ERROR).getFirst(), 
t.getMessage());
+    if (t != null) {
+      String message = t.getMessage();
+      if (StringUtils.isEmpty(message)) {
+        message = ExceptionUtils.getMessage(t);
+      }
+
+      return String.format(MESSAGES.get(INTERNAL_ERROR).getFirst(), message);
     } else {
       return getInternalErrorMessage();
     }
-
   }
 
   public static String concat(String[] args) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java
index da59e8a..68104e7 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java
@@ -22,6 +22,7 @@ package org.apache.tajo.engine.codegen;
 import org.apache.tajo.catalog.CatalogUtil;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.eval.ExprTestBase;
 import org.apache.tajo.exception.TajoException;
 import org.junit.Test;
@@ -111,12 +112,12 @@ public class TestEvalCodeGenerator extends ExprTestBase {
     testSimpleEval("select (1 > null AND false)", new String[] {"f"}); // 
unknown - false -> false
     testSimpleEval("select (1::int8 > null) is null", new String[] {"t"});
 
-    testSimpleEval("select 1 = null;", new String [] {""});
-    testSimpleEval("select 1 <> null;", new String [] {""});
-    testSimpleEval("select 1 > null;", new String [] {""});
-    testSimpleEval("select 1 >= null;", new String [] {""});
-    testSimpleEval("select 1 < null;", new String [] {""});
-    testSimpleEval("select 1 <= null;", new String [] {""});
+    testSimpleEval("select 1 = null;", new String [] 
{NullDatum.get().toString()});
+    testSimpleEval("select 1 <> null;", new String [] 
{NullDatum.get().toString()});
+    testSimpleEval("select 1 > null;", new String [] 
{NullDatum.get().toString()});
+    testSimpleEval("select 1 >= null;", new String [] 
{NullDatum.get().toString()});
+    testSimpleEval("select 1 < null;", new String [] 
{NullDatum.get().toString()});
+    testSimpleEval("select 1 <= null;", new String [] 
{NullDatum.get().toString()});
 
     testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col1 from 
table1;", new String [] {"t"});
     testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col2 from 
table1;", new String [] {"f"});

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
index 18d6ba2..81ba9f8 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
@@ -317,7 +317,7 @@ public class ExprTestBase {
         } else if (outTuple.type(i) == Type.TIME) {
           outTupleAsChars = TimeDatum.asChars(outTuple.getTimeDate(i), 
timeZone, false);
         } else {
-          outTupleAsChars = outTuple.getText(i);
+          outTupleAsChars = outTuple.asDatum(i).toString();
         }
         assertEquals(query, expected[i], outTupleAsChars);
       }

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/NullTestFunction.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/NullTestFunction.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/NullTestFunction.java
new file mode 100644
index 0000000..816605f
--- /dev/null
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/NullTestFunction.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.function;
+
+import org.apache.tajo.common.TajoDataTypes.Type;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.function.annotation.Description;
+import org.apache.tajo.engine.function.annotation.ParamTypes;
+import org.apache.tajo.plan.function.GeneralFunction;
+import org.apache.tajo.storage.Tuple;
+
+@Description(
+    functionName = "null_test",
+    description = "Test null safe function. Result is null.",
+    example = "> SELECT null_test();",
+    returnType = Type.NULL_TYPE,
+    paramTypes = {@ParamTypes(paramTypes = {})}
+)
+public class NullTestFunction extends GeneralFunction {
+
+  public NullTestFunction() {
+    super(NoArgs);
+  }
+
+  @Override
+  public Datum eval(Tuple params) {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestConditionalExpressions.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestConditionalExpressions.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestConditionalExpressions.java
index c214f66..691579c 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestConditionalExpressions.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestConditionalExpressions.java
@@ -20,6 +20,7 @@ package org.apache.tajo.engine.function;
 
 import org.apache.tajo.catalog.CatalogUtil;
 import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.exception.UndefinedFunctionException;
 import org.apache.tajo.common.TajoDataTypes;
 import org.apache.tajo.engine.eval.ExprTestBase;
@@ -67,7 +68,7 @@ public class TestConditionalExpressions extends ExprTestBase {
         new String[]{"str2"});
     testEval(schema, "table1", ",str2",
         "SELECT CASE WHEN col1 IS NOT NULL THEN col2 ELSE NULL END FROM 
table1",
-        new String[]{""});
+        new String[]{NullDatum.get().toString()});
   }
 
   @Test
@@ -117,7 +118,7 @@ public class TestConditionalExpressions extends 
ExprTestBase {
 
     testEval(schema, "table1", "1,2,3",
         "SELECT CASE col1 WHEN 1 THEN NULL WHEN 2 THEN 2 ELSE 3 END FROM 
table1",
-        new String [] {""});
+        new String [] {NullDatum.get().toString()});
     testEval(schema, "table1", "1,2,3",
         "SELECT CASE col2 WHEN 1 THEN NULL WHEN 2 THEN 2 ELSE 3 END FROM 
table1",
         new String [] {"2"});
@@ -133,7 +134,7 @@ public class TestConditionalExpressions extends 
ExprTestBase {
         new String [] {"2"});
     testEval(schema, "table1", "1,2,3",
         "SELECT CASE col3 WHEN 1 THEN NULL WHEN 2 THEN 2 ELSE NULL END FROM 
table1",
-        new String [] {""});
+        new String [] {NullDatum.get().toString()});
   }
 
   @Test
@@ -144,7 +145,7 @@ public class TestConditionalExpressions extends 
ExprTestBase {
     testSimpleEval("select coalesce('value1', null, 'value3');", new 
String[]{"value1"});
     testSimpleEval("select coalesce(null, 'value2', 'value3');", new 
String[]{"value2"});
     testSimpleEval("select coalesce('value1');", new String[]{"value1"});
-    testSimpleEval("select coalesce(null);", new String[]{""});
+    testSimpleEval("select coalesce(null);", new 
String[]{NullDatum.get().toString()});
 
     //no matched function
     try {
@@ -163,7 +164,7 @@ public class TestConditionalExpressions extends 
ExprTestBase {
     testSimpleEval("select coalesce(1, null, 3);", new String[]{"1"});
     testSimpleEval("select coalesce(null, 2, 3);", new String[]{"2"});
     testSimpleEval("select coalesce(1);", new String[]{"1"});
-    testSimpleEval("select coalesce(null);", new String[]{""});
+    testSimpleEval("select coalesce(null);", new 
String[]{NullDatum.get().toString()});
 
     //no matched function
     try {
@@ -182,7 +183,7 @@ public class TestConditionalExpressions extends 
ExprTestBase {
     testSimpleEval("select coalesce(1.0, null, 3.0);", new String[]{"1.0"});
     testSimpleEval("select coalesce(null, 2.0, 3.0);", new String[]{"2.0"});
     testSimpleEval("select coalesce(1.0);", new String[]{"1.0"});
-    testSimpleEval("select coalesce(null);", new String[]{""});
+    testSimpleEval("select coalesce(null);", new 
String[]{NullDatum.get().toString()});
 
     //no matched function
     try {

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestJsonFunctions.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestJsonFunctions.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestJsonFunctions.java
index 1792075..fc5e8e1 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestJsonFunctions.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestJsonFunctions.java
@@ -19,6 +19,7 @@
 package org.apache.tajo.engine.function;
 
 
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.eval.ExprTestBase;
 import org.apache.tajo.exception.TajoException;
 import org.junit.Test;
@@ -41,9 +42,9 @@ public class TestJsonFunctions extends ExprTestBase {
     testSimpleEval("select json_array_get('" + JSON_ARRAY + "', 2)", new 
String[]{"300"});
     testSimpleEval("select json_array_get('" + JSON_ARRAY + "', -1)", new 
String[]{"500"});
     testSimpleEval("select json_array_get('" + JSON_ARRAY + "', -2)", new 
String[]{"400"});
-    testSimpleEval("select json_array_get('" + JSON_ARRAY + "', 10)", new 
String[]{""});
-    testSimpleEval("select json_array_get('" + JSON_ARRAY + "', -10)", new 
String[]{""});
-    testSimpleEval("select json_array_get('" + JSON_EMPTY_ARRAY + "', 0)", new 
String[]{""});
+    testSimpleEval("select json_array_get('" + JSON_ARRAY + "', 10)", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select json_array_get('" + JSON_ARRAY + "', -10)", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select json_array_get('" + JSON_EMPTY_ARRAY + "', 0)", new 
String[]{NullDatum.get().toString()});
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestMathFunctions.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestMathFunctions.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestMathFunctions.java
index 4b0303f..a43e4d3 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestMathFunctions.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestMathFunctions.java
@@ -19,6 +19,7 @@
 package org.apache.tajo.engine.function;
 
 import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.eval.ExprTestBase;
 import org.apache.tajo.exception.TajoException;
 import org.junit.Test;
@@ -396,8 +397,8 @@ public class TestMathFunctions extends ExprTestBase {
     testSimpleEval("select pow(9,3) as col1 ", new 
String[]{String.valueOf(Math.pow(9, 3))});
     testSimpleEval("select pow(1.0,3) as col1 ", new 
String[]{String.valueOf(Math.pow(1.0, 3))});
     testSimpleEval("select pow(20.1,3.1) as col1 ", new 
String[]{String.valueOf(Math.pow(20.1, 3.1))});
-    testSimpleEval("select pow(null,3.1) as col1 ", new String[]{""});
-    testSimpleEval("select pow(20.1,null) as col1 ", new String[]{""});
+    testSimpleEval("select pow(null,3.1) as col1 ", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select pow(20.1,null) as col1 ", new 
String[]{NullDatum.get().toString()});
 
     Schema schema = new Schema();
     schema.addColumn("col1", FLOAT4);
@@ -465,6 +466,6 @@ public class TestMathFunctions extends ExprTestBase {
     schema.addColumn("col1", FLOAT8);
     schema.addColumn("col2", INT4);
 
-    testEval(schema, "table1", ",", "select round(col1, col2) from table1", 
new String[]{""});
+    testEval(schema, "table1", ",", "select round(col1, col2) from table1", 
new String[]{NullDatum.get().toString()});
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestPatternMatchingPredicates.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestPatternMatchingPredicates.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestPatternMatchingPredicates.java
index 50a8f35..eb0bd96 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestPatternMatchingPredicates.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestPatternMatchingPredicates.java
@@ -19,6 +19,7 @@
 package org.apache.tajo.engine.function;
 
 import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.eval.ExprTestBase;
 import org.apache.tajo.exception.TajoException;
 import org.junit.Test;
@@ -33,8 +34,8 @@ public class TestPatternMatchingPredicates extends 
ExprTestBase {
     schema.addColumn("col1", TEXT);
 
     // test for null values
-    testEval(schema, "table1", ",", "select col1 like 'a%' from table1", new 
String[]{""});
-    testSimpleEval("select null like 'a%'", new String[]{""});
+    testEval(schema, "table1", ",", "select col1 like 'a%' from table1", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select null like 'a%'", new 
String[]{NullDatum.get().toString()});
 
     testEval(schema, "table1", "abc", "select col1 like '%c' from table1", new 
String[]{"t"});
     testEval(schema, "table1", "abc", "select col1 like 'a%' from table1", new 
String[]{"t"});

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
index 366d8ed..751a243 100644
--- 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
@@ -21,6 +21,7 @@ package org.apache.tajo.engine.function;
 
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.engine.eval.ExprTestBase;
 import org.apache.tajo.exception.TajoException;
 import org.junit.Test;
@@ -126,9 +127,9 @@ public class TestStringOperatorsAndFunctions extends 
ExprTestBase {
     testSimpleEval("select regexp_replace('abcdef','bc','--') as col1 ", new 
String[]{"a--def"});
 
     // null test
-    testSimpleEval("select regexp_replace(null, 'bc', '--') as col1 ", new 
String[]{""});
-    testSimpleEval("select regexp_replace('abcdef', null, '--') as col1 ", new 
String[]{""});
-    testSimpleEval("select regexp_replace('abcdef','bc', null) as col1 ", new 
String[]{""});
+    testSimpleEval("select regexp_replace(null, 'bc', '--') as col1 ", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select regexp_replace('abcdef', null, '--') as col1 ", new 
String[]{NullDatum.get().toString()});
+    testSimpleEval("select regexp_replace('abcdef','bc', null) as col1 ", new 
String[]{NullDatum.get().toString()});
 
     Schema schema = new Schema();
     schema.addColumn("col1", TEXT);
@@ -141,9 +142,9 @@ public class TestStringOperatorsAndFunctions extends 
ExprTestBase {
 
     // null test from a table
     testEval(schema, "table1", ",(^--|--$),ab", "select regexp_replace(col1, 
col2, col3) as str from table1",
-        new String[]{""});
+        new String[]{NullDatum.get().toString()});
     testEval(schema, "table1", "------,(^--|--$),", "select 
regexp_replace(col1, col2, col3) as str from table1",
-        new String[]{""});
+        new String[]{NullDatum.get().toString()});
   }
 
   @Test
@@ -305,7 +306,7 @@ public class TestStringOperatorsAndFunctions extends 
ExprTestBase {
       new 
String[]{"59ff99b0e274eb3d8e10f221b6b949bfc1244d2a1226c5c720062fb03d82272be633e4a0f2babccffbfdff7cc1cb06fb"});
     testSimpleEval("select digest('tajo', 'sha512') as col1 ", 
       new 
String[]{"ee8ba254d331ddfb1bca9aaf0c4b8c58aea5331928cbd20168c87828afb853b0c096af71ec69a23b669217a1dddd2934edaac33b1296fe526b22abd28a15c4b3"});
-    testSimpleEval("select digest('tajo', 'not') as col1 ", new String[]{""});
+    testSimpleEval("select digest('tajo', 'not') as col1 ", new 
String[]{NullDatum.get().toString()});
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestUserDefinedFunctions.java
----------------------------------------------------------------------
diff --git 
a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestUserDefinedFunctions.java
 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestUserDefinedFunctions.java
new file mode 100644
index 0000000..a179e74
--- /dev/null
+++ 
b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestUserDefinedFunctions.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.function;
+
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.NullDatum;
+import org.apache.tajo.engine.eval.ExprTestBase;
+import org.apache.tajo.exception.TajoException;
+import org.junit.Test;
+
+import static org.apache.tajo.common.TajoDataTypes.Type.BOOLEAN;
+
+public class TestUserDefinedFunctions extends ExprTestBase {
+
+  @Test
+  public void testNullHandling() throws TajoException {
+    testSimpleEval("select null_test()", new 
String[]{NullDatum.get().toString()});
+  }
+
+  @Test
+  public void testNullHandling2() throws TajoException {
+    Schema schema = new Schema();
+    schema.addColumn("col1", BOOLEAN);
+
+    testEval(schema, "table1", "", "select null_test() from table1", new 
String[]{NullDatum.get().toString()});
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-core/src/main/java/org/apache/tajo/master/QueryInProgress.java
----------------------------------------------------------------------
diff --git 
a/tajo-core/src/main/java/org/apache/tajo/master/QueryInProgress.java 
b/tajo-core/src/main/java/org/apache/tajo/master/QueryInProgress.java
index ba70bad..609ceff 100644
--- a/tajo-core/src/main/java/org/apache/tajo/master/QueryInProgress.java
+++ b/tajo-core/src/main/java/org/apache/tajo/master/QueryInProgress.java
@@ -269,7 +269,7 @@ public class QueryInProgress {
       // if any error occurs, print outs the error message
       if (this.queryInfo.getQueryState() == QueryState.QUERY_FAILED ||
           this.queryInfo.getQueryState() == QueryState.QUERY_ERROR) {
-        LOG.warn(queryId + " is stopped because " + 
queryInfo.getLastMessage());
+        LOG.error(queryId + " is stopped because " + 
queryInfo.getLastMessage());
       }
 
       // terminal state will let client to retrieve a query result

http://git-wip-us.apache.org/repos/asf/tajo/blob/e65f4a2b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
----------------------------------------------------------------------
diff --git 
a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java 
b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
index c7b900e..febadc0 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
@@ -23,6 +23,7 @@ import org.apache.tajo.OverridableConf;
 import org.apache.tajo.catalog.FunctionDesc;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.plan.function.FunctionInvoke;
 import org.apache.tajo.plan.function.FunctionInvokeContext;
 import org.apache.tajo.storage.Tuple;
@@ -57,7 +58,12 @@ public class GeneralFunctionEval extends FunctionEval {
   @SuppressWarnings("unchecked")
   public Datum eval(Tuple tuple) {
     super.eval(tuple);
-    return funcInvoke.eval(evalParams(tuple));
+    Datum datum = funcInvoke.eval(evalParams(tuple));
+    if (datum == null) {
+      return NullDatum.get();
+    } else {
+      return datum;
+    }
   }
 
        @Override

Reply via email to