diff --git ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFConcat.java ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFConcat.java index 8d48799..b0089f0 100644 --- ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFConcat.java +++ ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFConcat.java @@ -55,7 +55,6 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { // Loop through all the inputs to determine the appropriate return type/length. - // Either all arguments are binary, or all columns are non-binary. // Return type: // All VARCHAR inputs: return VARCHAR // All BINARY inputs: return BINARY @@ -79,21 +78,16 @@ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumen case BINARY: fixedLengthReturnValue = false; if (returnType != currentCategory) { - throw new UDFArgumentException( - "CONCAT cannot take a mix of binary and non-binary arguments"); + // mix of binary/non-binary args + returnType = PrimitiveCategory.STRING; } break; case VARCHAR: - if (returnType == PrimitiveCategory.BINARY) { - throw new UDFArgumentException( - "CONCAT cannot take a mix of binary and non-binary arguments"); + if (!fixedLengthReturnValue) { + returnType = PrimitiveCategory.STRING; } break; default: - if (returnType == PrimitiveCategory.BINARY) { - throw new UDFArgumentException( - "CONCAT cannot take a mix of binary and non-binary arguments"); - } returnType = PrimitiveCategory.STRING; fixedLengthReturnValue = false; break; diff --git ql/src/test/queries/clientpositive/udf_concat.q ql/src/test/queries/clientpositive/udf_concat.q index f642f6a..3d3c85d 100644 --- ql/src/test/queries/clientpositive/udf_concat.q +++ ql/src/test/queries/clientpositive/udf_concat.q @@ -13,3 +13,9 @@ SELECT concat(1), concat('1234', 'abc', 'extra argument') FROM src LIMIT 1; + +-- binary/mixed +SELECT + concat(cast('ab' as binary), cast('cd' as binary)), + concat('ab', cast('cd' as binary)) +FROM src LIMIT 1; diff --git ql/src/test/results/clientpositive/udf_concat.q.out ql/src/test/results/clientpositive/udf_concat.q.out index cd5c3db..f7fe752 100644 --- ql/src/test/results/clientpositive/udf_concat.q.out +++ ql/src/test/results/clientpositive/udf_concat.q.out @@ -43,3 +43,20 @@ POSTHOOK: type: QUERY POSTHOOK: Input: default@src #### A masked pattern was here #### ab abc NULL NULL a NULL 123a 12 1 1234abcextra argument +PREHOOK: query: -- binary/mixed +SELECT + concat(cast('ab' as binary), cast('cd' as binary)), + concat('ab', cast('cd' as binary)) +FROM src LIMIT 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: -- binary/mixed +SELECT + concat(cast('ab' as binary), cast('cd' as binary)), + concat('ab', cast('cd' as binary)) +FROM src LIMIT 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +abcd abcd diff --git serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/primitive/PrimitiveObjectInspectorUtils.java serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/primitive/PrimitiveObjectInspectorUtils.java index ef614b3..a931578 100644 --- serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/primitive/PrimitiveObjectInspectorUtils.java +++ serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/primitive/PrimitiveObjectInspectorUtils.java @@ -21,6 +21,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.nio.charset.CharacterCodingException; import java.sql.Date; import java.sql.Timestamp; import java.util.HashMap; @@ -773,6 +774,16 @@ public static String getString(Object o, PrimitiveObjectInspector oi) { case VOID: result = null; break; + case BINARY: + try { + byte[] bytes = ((BinaryObjectInspector) oi).getPrimitiveWritableObject(o).getBytes(); + int byteLen = ((BinaryObjectInspector) oi).getPrimitiveWritableObject(o).getLength(); + result = Text.decode(bytes, 0, byteLen); + } catch (CharacterCodingException err) { + // we tried .. + result = null; + } + break; case BOOLEAN: result = String.valueOf((((BooleanObjectInspector) oi).get(o))); break;