Index: ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFUtils.java =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFUtils.java +++ ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFUtils.java @@ -37,6 +37,7 @@ import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.IdentityConverter; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory.ObjectInspectorOptions; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils.ObjectInspectorCopyOption; +import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.primitive.VoidObjectInspector; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; @@ -48,23 +49,23 @@ public final class GenericUDFUtils { /** * Checks if b is the first byte of a UTF-8 character. - * + * */ public static boolean isUtfStartByte(byte b) { return (b & 0xC0) != 0x80; } /** * This class helps to find the return ObjectInspector for a GenericUDF. - * + * * In many cases like CASE and IF, the GenericUDF is returning a value out of * several possibilities. However these possibilities may not always have the * same ObjectInspector. - * + * * This class will help detect whether all possibilities have exactly the same * ObjectInspector. If not, then we need to convert the Objects to the same * ObjectInspector. - * + * * A special case is when some values are constant NULL. In this case we can * use the same ObjectInspector. */ @@ -88,7 +89,7 @@ /** * Update returnObjectInspector and valueInspectorsAreTheSame based on the * ObjectInspector seen. - * + * * @return false if there is a type mismatch */ public boolean update(ObjectInspector oi) throws UDFArgumentTypeException { @@ -145,7 +146,13 @@ * Returns the ObjectInspector of the return value. */ public ObjectInspector get() { - return returnObjectInspector; + if (returnObjectInspector == null) { + // We didn't get any non-NULL arguments, so this function returns + // VoidType. + return PrimitiveObjectInspectorFactory.writableVoidObjectInspector; + } else { + return returnObjectInspector; + } } /** Index: ql/src/test/queries/clientpositive/udf_coalesce.q =================================================================== --- ql/src/test/queries/clientpositive/udf_coalesce.q +++ ql/src/test/queries/clientpositive/udf_coalesce.q @@ -19,7 +19,8 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1; SELECT COALESCE(1), @@ -39,7 +40,8 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1; EXPLAIN Index: ql/src/test/results/clientpositive/udf_coalesce.q.out =================================================================== --- ql/src/test/results/clientpositive/udf_coalesce.q.out +++ ql/src/test/results/clientpositive/udf_coalesce.q.out @@ -29,7 +29,8 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1 PREHOOK: type: QUERY POSTHOOK: query: EXPLAIN @@ -50,11 +51,12 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1 POSTHOOK: type: QUERY ABSTRACT SYNTAX TREE: - (TOK_QUERY (TOK_FROM (TOK_TABREF (TOK_TABNAME src))) (TOK_INSERT (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE)) (TOK_SELECT (TOK_SELEXPR (TOK_FUNCTION COALESCE 1)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1 2)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1 TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL TOK_NULL 3)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 4 TOK_NULL TOK_NULL TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1' '2')) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL '2')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1' TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL TOK_NULL '3')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '4' TOK_NULL TOK_NULL TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1.0 2.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2.0 3.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 2.0 TOK_NULL 3.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE (TOK_FUNCTION IF TRUE TOK_NULL 0) TOK_NULL))) (TOK_LIMIT 1))) + (TOK_QUERY (TOK_FROM (TOK_TABREF (TOK_TABNAME src))) (TOK_INSERT (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE)) (TOK_SELECT (TOK_SELEXPR (TOK_FUNCTION COALESCE 1)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1 2)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1 TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL TOK_NULL 3)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 4 TOK_NULL TOK_NULL TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1' '2')) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL '2')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '1' TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL TOK_NULL '3')) (TOK_SELEXPR (TOK_FUNCTION COALESCE '4' TOK_NULL TOK_NULL TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 1.0 2.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL 2.0 3.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE 2.0 TOK_NULL 3.0)) (TOK_SELEXPR (TOK_FUNCTION COALESCE (TOK_FUNCTION IF TRUE TOK_NULL 0) TOK_NULL)) (TOK_SELEXPR (TOK_FUNCTION COALESCE TOK_NULL TOK_NULL))) (TOK_LIMIT 1))) STAGE DEPENDENCIES: Stage-1 is a root stage @@ -105,7 +107,9 @@ type: double expr: COALESCE(if(true, null, 0),null) type: int - outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7, _col8, _col9, _col10, _col11, _col12, _col13, _col14, _col15, _col16, _col17 + expr: COALESCE(null,null) + type: void + outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7, _col8, _col9, _col10, _col11, _col12, _col13, _col14, _col15, _col16, _col17, _col18 Limit File Output Operator compressed: false @@ -136,7 +140,8 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1 PREHOOK: type: QUERY PREHOOK: Input: default@src @@ -158,12 +163,13 @@ COALESCE(NULL, 2.0), COALESCE(NULL, 2.0, 3.0), COALESCE(2.0, NULL, 3.0), - COALESCE(IF(TRUE, NULL, 0), NULL) + COALESCE(IF(TRUE, NULL, 0), NULL), + COALESCE(NULL, NULL) FROM src LIMIT 1 POSTHOOK: type: QUERY POSTHOOK: Input: default@src #### A masked pattern was here #### -1 1 2 1 3 4 1 1 2 1 3 4 1.0 1.0 2.0 2.0 2.0 NULL +1 1 2 1 3 4 1 1 2 1 3 4 1.0 1.0 2.0 2.0 2.0 NULL NULL PREHOOK: query: EXPLAIN SELECT COALESCE(src_thrift.lint[1], 999), COALESCE(src_thrift.lintstring[0].mystring, '999'),