diff --git ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java index 49ec215..e10a2eb 100644 --- ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java +++ ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java @@ -25,11 +25,11 @@ import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils; /** - * GenericUDF Class for SQL construct - * "CASE WHEN a THEN b WHEN c THEN d [ELSE f] END". + * GenericUDF Class for SQL construct "CASE a WHEN b THEN c [ELSE f] END". * - * NOTES: 1. a and c should be boolean, or an exception will be thrown. 2. b, d - * and f should have the same TypeInfo, or an exception will be thrown. + * NOTES: 1. a and b should be compatible, or an exception will be + * thrown. 2. c and f should be compatible types, or an exception will be + * thrown. */ public class GenericUDFCase extends GenericUDF { private transient ObjectInspector[] argumentOIs; @@ -40,8 +40,8 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentTypeException { argumentOIs = arguments; - caseOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(); - returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(); + caseOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true); + returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true); boolean r = caseOIResolver.update(arguments[0]); assert (r); @@ -79,12 +79,13 @@ public Object evaluate(DeferredObject[] arguments) throws HiveException { Object exprValue = arguments[0].get(); for (int i = 1; i + 1 < arguments.length; i += 2) { Object caseKey = arguments[i].get(); - if (PrimitiveObjectInspectorUtils.comparePrimitiveObjects(exprValue, - (PrimitiveObjectInspector) argumentOIs[0], caseKey, - (PrimitiveObjectInspector) argumentOIs[i])) { + // May need to convert to common type to compare + PrimitiveObjectInspector caseOI = (PrimitiveObjectInspector) caseOIResolver.get(); + if (PrimitiveObjectInspectorUtils.comparePrimitiveObjects( + caseOIResolver.convertIfNecessary(exprValue, argumentOIs[0]), caseOI, + caseOIResolver.convertIfNecessary(caseKey, argumentOIs[i]), caseOI)) { Object caseValue = arguments[i + 1].get(); - return returnOIResolver.convertIfNecessary(caseValue, - argumentOIs[i + 1]); + return returnOIResolver.convertIfNecessary(caseValue, argumentOIs[i + 1]); } } // Process else statement diff --git ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFWhen.java ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFWhen.java index 554af2c..6ffdbd8 100644 --- ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFWhen.java +++ ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFWhen.java @@ -25,11 +25,11 @@ import org.apache.hadoop.hive.serde2.objectinspector.primitive.BooleanObjectInspector; /** - * GenericUDF Class for SQL construct "CASE a WHEN b THEN c [ELSE f] END". + * GenericUDF Class for SQL construct + * "CASE WHEN a THEN b WHEN c THEN d [ELSE f] END". * - * NOTES: 1. a and b should have the same TypeInfo, or an exception will be - * thrown. 2. c and f should have the same TypeInfo, or an exception will be - * thrown. + * NOTES: 1. a and c should be boolean, or an exception will be thrown. 2. b, d + * and f should be common types, or an exception will be thrown. */ public class GenericUDFWhen extends GenericUDF { private transient ObjectInspector[] argumentOIs; @@ -39,7 +39,7 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentTypeException { argumentOIs = arguments; - returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(); + returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true); for (int i = 0; i + 1 < arguments.length; i += 2) { if (!arguments[i].getTypeName().equals(serdeConstants.BOOLEAN_TYPE_NAME)) { diff --git ql/src/test/queries/clientnegative/udf_case_type_wrong.q ql/src/test/queries/clientnegative/udf_case_type_wrong.q deleted file mode 100644 index 2fb5ff7..0000000 --- ql/src/test/queries/clientnegative/udf_case_type_wrong.q +++ /dev/null @@ -1,6 +0,0 @@ -SELECT CASE '1' - WHEN 1 THEN 2 - WHEN 3 THEN 4 - ELSE 5 - END -FROM src LIMIT 1; diff --git ql/src/test/queries/clientnegative/udf_case_type_wrong2.q ql/src/test/queries/clientnegative/udf_case_type_wrong2.q deleted file mode 100644 index 5772dc1..0000000 --- ql/src/test/queries/clientnegative/udf_case_type_wrong2.q +++ /dev/null @@ -1,6 +0,0 @@ -SELECT CASE 1 - WHEN 1 THEN '2' - WHEN 3 THEN 4 - ELSE 5 - END -FROM src LIMIT 1; diff --git ql/src/test/queries/clientnegative/udf_case_type_wrong3.q ql/src/test/queries/clientnegative/udf_case_type_wrong3.q deleted file mode 100644 index 5aaf018..0000000 --- ql/src/test/queries/clientnegative/udf_case_type_wrong3.q +++ /dev/null @@ -1,6 +0,0 @@ -SELECT CASE 1 - WHEN 1 THEN NULL - WHEN 3 THEN '2' - ELSE 7 - END -FROM src LIMIT 1; diff --git ql/src/test/queries/clientnegative/udf_when_type_wrong2.q ql/src/test/queries/clientnegative/udf_when_type_wrong2.q deleted file mode 100644 index 79fa65f..0000000 --- ql/src/test/queries/clientnegative/udf_when_type_wrong2.q +++ /dev/null @@ -1,6 +0,0 @@ -SELECT CASE - WHEN 1=2 THEN '2' - WHEN 3=4 THEN 4 - ELSE 5 - END -FROM src LIMIT 1; diff --git ql/src/test/queries/clientnegative/udf_when_type_wrong3.q ql/src/test/queries/clientnegative/udf_when_type_wrong3.q deleted file mode 100644 index 8bb5fdd..0000000 --- ql/src/test/queries/clientnegative/udf_when_type_wrong3.q +++ /dev/null @@ -1,6 +0,0 @@ -SELECT CASE - WHEN 1=2 THEN '2' - WHEN 3=4 THEN '5' - ELSE 5.3 - END -FROM src LIMIT 1; diff --git ql/src/test/queries/clientpositive/udf_case.q ql/src/test/queries/clientpositive/udf_case.q index 03f9f9f..b2c1ddc 100644 --- ql/src/test/queries/clientpositive/udf_case.q +++ ql/src/test/queries/clientpositive/udf_case.q @@ -63,3 +63,20 @@ FROM src tablesample (1 rows); SELECT CASE 1 WHEN 1 THEN 'yo' ELSE reflect('java.lang.String', 'bogus', 1) END FROM src tablesample (1 rows); + +-- Allow compatible types in when/return type +SELECT CASE 1 + WHEN 1 THEN 123.0BD + ELSE 0.0BD + END, + CASE 1 + WHEN 1.0 THEN 123 + WHEN 2 THEN 1.0 + ELSE 0.0BD + END, + CASE 'abc' + WHEN cast('abc' as varchar(3)) THEN 'abcd' + WHEN 'efg' THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows); diff --git ql/src/test/queries/clientpositive/udf_when.q ql/src/test/queries/clientpositive/udf_when.q index ec8c42e..f29094b 100644 --- ql/src/test/queries/clientpositive/udf_when.q +++ ql/src/test/queries/clientpositive/udf_when.q @@ -57,3 +57,20 @@ SELECT CASE WHEN 28=28 THEN NULL END FROM src tablesample (1 rows); + +-- Allow compatible types to be used in return value +SELECT CASE + WHEN 1=1 THEN 123.0BD + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 123 + WHEN 1=2 THEN 1.0 + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 'abcd' + WHEN 1=2 THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows); diff --git ql/src/test/results/clientnegative/udf_case_type_wrong.q.out ql/src/test/results/clientnegative/udf_case_type_wrong.q.out deleted file mode 100644 index 3314002..0000000 --- ql/src/test/results/clientnegative/udf_case_type_wrong.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10016]: Line 2:13 Argument type mismatch '1': The expressions after WHEN should have the same type with that after CASE: "string" is expected but "int" is found diff --git ql/src/test/results/clientnegative/udf_case_type_wrong2.q.out ql/src/test/results/clientnegative/udf_case_type_wrong2.q.out deleted file mode 100644 index 5be7d66..0000000 --- ql/src/test/results/clientnegative/udf_case_type_wrong2.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10016]: Line 3:20 Argument type mismatch '4': The expressions after THEN should have the same type: "string" is expected but "int" is found diff --git ql/src/test/results/clientnegative/udf_case_type_wrong3.q.out ql/src/test/results/clientnegative/udf_case_type_wrong3.q.out deleted file mode 100644 index 901d9a9..0000000 --- ql/src/test/results/clientnegative/udf_case_type_wrong3.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10016]: Line 4:13 Argument type mismatch '7': The expression after ELSE should have the same type as those after THEN: "string" is expected but "int" is found diff --git ql/src/test/results/clientnegative/udf_when_type_wrong2.q.out ql/src/test/results/clientnegative/udf_when_type_wrong2.q.out deleted file mode 100644 index e94e6e3..0000000 --- ql/src/test/results/clientnegative/udf_when_type_wrong2.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10016]: Line 3:22 Argument type mismatch '4': The expressions after THEN should have the same type: "string" is expected but "int" is found diff --git ql/src/test/results/clientnegative/udf_when_type_wrong3.q.out ql/src/test/results/clientnegative/udf_when_type_wrong3.q.out deleted file mode 100644 index 7d4c12f..0000000 --- ql/src/test/results/clientnegative/udf_when_type_wrong3.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10016]: Line 4:13 Argument type mismatch '5.3': The expression after ELSE should have the same type as those after THEN: "string" is expected but "double" is found diff --git ql/src/test/results/clientpositive/udf_case.q.out ql/src/test/results/clientpositive/udf_case.q.out index 4a59a8c..0c55e74 100644 --- ql/src/test/results/clientpositive/udf_case.q.out +++ ql/src/test/results/clientpositive/udf_case.q.out @@ -172,3 +172,42 @@ POSTHOOK: type: QUERY POSTHOOK: Input: default@src #### A masked pattern was here #### yo +PREHOOK: query: -- Allow compatible types in when/return type +SELECT CASE 1 + WHEN 1 THEN 123.0BD + ELSE 0.0BD + END, + CASE 1 + WHEN 1.0 THEN 123 + WHEN 2 THEN 1.0 + ELSE 0.0BD + END, + CASE 'abc' + WHEN cast('abc' as varchar(3)) THEN 'abcd' + WHEN 'efg' THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows) +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: -- Allow compatible types in when/return type +SELECT CASE 1 + WHEN 1 THEN 123.0BD + ELSE 0.0BD + END, + CASE 1 + WHEN 1.0 THEN 123 + WHEN 2 THEN 1.0 + ELSE 0.0BD + END, + CASE 'abc' + WHEN cast('abc' as varchar(3)) THEN 'abcd' + WHEN 'efg' THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows) +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +123 123 abcd diff --git ql/src/test/results/clientpositive/udf_when.q.out ql/src/test/results/clientpositive/udf_when.q.out index 367f48a..bff2f98 100644 --- ql/src/test/results/clientpositive/udf_when.q.out +++ ql/src/test/results/clientpositive/udf_when.q.out @@ -155,3 +155,42 @@ POSTHOOK: type: QUERY POSTHOOK: Input: default@src #### A masked pattern was here #### 2 9 14 NULL 24 NULL +PREHOOK: query: -- Allow compatible types to be used in return value +SELECT CASE + WHEN 1=1 THEN 123.0BD + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 123 + WHEN 1=2 THEN 1.0 + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 'abcd' + WHEN 1=2 THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows) +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: -- Allow compatible types to be used in return value +SELECT CASE + WHEN 1=1 THEN 123.0BD + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 123 + WHEN 1=2 THEN 1.0 + ELSE 0.0BD + END, + CASE + WHEN 1=1 THEN 'abcd' + WHEN 1=2 THEN cast('efgh' as varchar(10)) + ELSE cast('ijkl' as char(4)) + END +FROM src tablesample (1 rows) +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +123 123 abcd