diff --git ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java index 2308bf4..7ca950d 100644 --- ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java +++ ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java @@ -811,8 +811,9 @@ public static synchronized TypeInfo getCommonClassForComparison(TypeInfo a, Type if (pgA == pgB) { // grouping is same, but category is not. if (pgA == PrimitiveGrouping.DATE_GROUP) { - // we got timestamp & date and timestamp has higher precedence than date - return TypeInfoFactory.timestampTypeInfo; + Integer ai = TypeInfoUtils.dateTypes.get(pcA); + Integer bi = TypeInfoUtils.dateTypes.get(pcB); + return (ai > bi) ? a : b; } } // handle string types properly @@ -854,27 +855,48 @@ public static PrimitiveCategory getPrimitiveCommonCategory(TypeInfo a, TypeInfo PrimitiveCategory pcA = ((PrimitiveTypeInfo)a).getPrimitiveCategory(); PrimitiveCategory pcB = ((PrimitiveTypeInfo)b).getPrimitiveCategory(); + if (pcA == pcB) { + // Same primitive category + return pcA; + } + PrimitiveGrouping pgA = PrimitiveObjectInspectorUtils.getPrimitiveGrouping(pcA); PrimitiveGrouping pgB = PrimitiveObjectInspectorUtils.getPrimitiveGrouping(pcB); - // handle string types properly - if (pgA == PrimitiveGrouping.STRING_GROUP && pgB == PrimitiveGrouping.STRING_GROUP) { - return PrimitiveCategory.STRING; - } - if (pgA == PrimitiveGrouping.DATE_GROUP && pgB == PrimitiveGrouping.STRING_GROUP) { - return PrimitiveCategory.STRING; + if (pgA == pgB) { + // Equal groups, return what we can handle + switch (pgA) { + case NUMERIC_GROUP: { + Integer ai = TypeInfoUtils.numericTypes.get(pcA); + Integer bi = TypeInfoUtils.numericTypes.get(pcB); + return (ai > bi) ? pcA : pcB; + } + case DATE_GROUP: { + Integer ai = TypeInfoUtils.dateTypes.get(pcA); + Integer bi = TypeInfoUtils.dateTypes.get(pcB); + return (ai > bi) ? pcA : pcB; + } + case STRING_GROUP: { + // handle string types properly + return PrimitiveCategory.STRING; + } + default: + break; + } } - if (pgB == PrimitiveGrouping.DATE_GROUP && pgA == PrimitiveGrouping.STRING_GROUP) { - return PrimitiveCategory.STRING; + + // Handle date-string common category and numeric-string common category + if (pgA == PrimitiveGrouping.STRING_GROUP + && (pgB == PrimitiveGrouping.DATE_GROUP || pgB == PrimitiveGrouping.NUMERIC_GROUP)) { + return pcA; } - Integer ai = TypeInfoUtils.numericTypes.get(pcA); - Integer bi = TypeInfoUtils.numericTypes.get(pcB); - if (ai == null || bi == null) { - // If either is not a numeric type, return null. - return null; + if (pgB == PrimitiveGrouping.STRING_GROUP + && (pgA == PrimitiveGrouping.DATE_GROUP || pgA == PrimitiveGrouping.NUMERIC_GROUP)) { + return pcB; } - return (ai > bi) ? pcA : pcB; + // We could not find a common category, return null + return null; } /** diff --git ql/src/test/queries/clientpositive/date_timestamp_prec.q ql/src/test/queries/clientpositive/date_timestamp_prec.q new file mode 100644 index 0000000..b25b13b --- /dev/null +++ ql/src/test/queries/clientpositive/date_timestamp_prec.q @@ -0,0 +1,8 @@ +create table mytable (i integer, d date); + +insert overwrite table mytable + select 1, cast('2011-01-01' as date) from src tablesample (1 rows); + +select i, coalesce(d, cast(d as timestamp)) from mytable; + +drop table mytable; diff --git ql/src/test/results/clientpositive/date_timestamp_prec.q.out ql/src/test/results/clientpositive/date_timestamp_prec.q.out new file mode 100644 index 0000000..764d1b5 --- /dev/null +++ ql/src/test/results/clientpositive/date_timestamp_prec.q.out @@ -0,0 +1,37 @@ +PREHOOK: query: create table mytable (i integer, d date) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@mytable +POSTHOOK: query: create table mytable (i integer, d date) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@mytable +PREHOOK: query: insert overwrite table mytable + select 1, cast('2011-01-01' as date) from src tablesample (1 rows) +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Output: default@mytable +POSTHOOK: query: insert overwrite table mytable + select 1, cast('2011-01-01' as date) from src tablesample (1 rows) +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Output: default@mytable +POSTHOOK: Lineage: mytable.d EXPRESSION [] +POSTHOOK: Lineage: mytable.i SIMPLE [] +PREHOOK: query: select i, coalesce(d, cast(d as timestamp)) from mytable +PREHOOK: type: QUERY +PREHOOK: Input: default@mytable +#### A masked pattern was here #### +POSTHOOK: query: select i, coalesce(d, cast(d as timestamp)) from mytable +POSTHOOK: type: QUERY +POSTHOOK: Input: default@mytable +#### A masked pattern was here #### +1 2011-01-01 00:00:00 +PREHOOK: query: drop table mytable +PREHOOK: type: DROPTABLE +PREHOOK: Input: default@mytable +PREHOOK: Output: default@mytable +POSTHOOK: query: drop table mytable +POSTHOOK: type: DROPTABLE +POSTHOOK: Input: default@mytable +POSTHOOK: Output: default@mytable diff --git ql/src/test/results/clientpositive/input8.q.out ql/src/test/results/clientpositive/input8.q.out index d76fc2b..0a930fe 100644 --- ql/src/test/results/clientpositive/input8.q.out +++ ql/src/test/results/clientpositive/input8.q.out @@ -108,7 +108,7 @@ POSTHOOK: Input: default@src1 POSTHOOK: Output: default@dest1 POSTHOOK: Lineage: dest1.c1 EXPRESSION [] POSTHOOK: Lineage: dest1.c2 EXPRESSION [(src1)src1.FieldSchema(name:key, type:string, comment:default), ] -POSTHOOK: Lineage: dest1.c3 SIMPLE [] +POSTHOOK: Lineage: dest1.c3 EXPRESSION [] PREHOOK: query: SELECT dest1.* FROM dest1 PREHOOK: type: QUERY PREHOOK: Input: default@dest1 diff --git ql/src/test/results/clientpositive/llap/subquery_null_agg.q.out ql/src/test/results/clientpositive/llap/subquery_null_agg.q.out index 0a9aa6c..78ee174 100644 --- ql/src/test/results/clientpositive/llap/subquery_null_agg.q.out +++ ql/src/test/results/clientpositive/llap/subquery_null_agg.q.out @@ -128,7 +128,7 @@ STAGE PLANS: predicate: ((_col1 = 0) or _col2 is null) (type: boolean) Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE Select Operator - expressions: null (type: double) + expressions: null (type: void) outputColumnNames: _col0 Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE File Output Operator diff --git ql/src/test/results/clientpositive/num_op_type_conv.q.out ql/src/test/results/clientpositive/num_op_type_conv.q.out index 00a4ca9..e5ad3d5 100644 --- ql/src/test/results/clientpositive/num_op_type_conv.q.out +++ ql/src/test/results/clientpositive/num_op_type_conv.q.out @@ -20,12 +20,12 @@ STAGE PLANS: alias: src Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: COMPLETE Select Operator - expressions: null (type: double), null (type: double), null (type: double), 1 (type: bigint), 0 (type: bigint), 0.0 (type: double) + expressions: null (type: double), null (type: double), null (type: void), 1 (type: bigint), 0 (type: bigint), 0.0 (type: double) outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5 - Statistics: Num rows: 500 Data size: 12024 Basic stats: COMPLETE Column stats: COMPLETE + Statistics: Num rows: 500 Data size: 12020 Basic stats: COMPLETE Column stats: COMPLETE Limit Number of rows: 1 - Statistics: Num rows: 1 Data size: 48 Basic stats: COMPLETE Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 44 Basic stats: COMPLETE Column stats: COMPLETE ListSink PREHOOK: query: SELECT null + 7, 1.0 - null, null + null, diff --git ql/src/test/results/clientpositive/ppd_constant_expr.q.out ql/src/test/results/clientpositive/ppd_constant_expr.q.out index cbe7654..494a1e2 100644 --- ql/src/test/results/clientpositive/ppd_constant_expr.q.out +++ ql/src/test/results/clientpositive/ppd_constant_expr.q.out @@ -108,7 +108,7 @@ POSTHOOK: Input: default@src1 POSTHOOK: Output: default@ppd_constant_expr POSTHOOK: Lineage: ppd_constant_expr.c1 EXPRESSION [] POSTHOOK: Lineage: ppd_constant_expr.c2 EXPRESSION [(src1)src1.FieldSchema(name:key, type:string, comment:default), ] -POSTHOOK: Lineage: ppd_constant_expr.c3 SIMPLE [] +POSTHOOK: Lineage: ppd_constant_expr.c3 EXPRESSION [] PREHOOK: query: SELECT ppd_constant_expr.* FROM ppd_constant_expr PREHOOK: type: QUERY PREHOOK: Input: default@ppd_constant_expr @@ -244,7 +244,7 @@ POSTHOOK: Input: default@src1 POSTHOOK: Output: default@ppd_constant_expr POSTHOOK: Lineage: ppd_constant_expr.c1 EXPRESSION [] POSTHOOK: Lineage: ppd_constant_expr.c2 EXPRESSION [(src1)src1.FieldSchema(name:key, type:string, comment:default), ] -POSTHOOK: Lineage: ppd_constant_expr.c3 SIMPLE [] +POSTHOOK: Lineage: ppd_constant_expr.c3 EXPRESSION [] PREHOOK: query: SELECT ppd_constant_expr.* FROM ppd_constant_expr PREHOOK: type: QUERY PREHOOK: Input: default@ppd_constant_expr diff --git ql/src/test/results/clientpositive/spark/subquery_null_agg.q.out ql/src/test/results/clientpositive/spark/subquery_null_agg.q.out index 144c3ec..945e2a7 100644 --- ql/src/test/results/clientpositive/spark/subquery_null_agg.q.out +++ ql/src/test/results/clientpositive/spark/subquery_null_agg.q.out @@ -137,7 +137,7 @@ STAGE PLANS: predicate: ((_col1 = 0) or _col2 is null) (type: boolean) Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE Select Operator - expressions: null (type: double) + expressions: null (type: void) outputColumnNames: _col0 Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE File Output Operator 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 024a8dd..9f7c318 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 @@ -1356,8 +1356,8 @@ public static PrimitiveGrouping getPrimitiveGrouping(PrimitiveCategory primitive return PrimitiveGrouping.STRING_GROUP; case BOOLEAN: return PrimitiveGrouping.BOOLEAN_GROUP; - case TIMESTAMP: case DATE: + case TIMESTAMP: case TIMESTAMPLOCALTZ: return PrimitiveGrouping.DATE_GROUP; case INTERVAL_YEAR_MONTH: diff --git serde/src/java/org/apache/hadoop/hive/serde2/typeinfo/TypeInfoUtils.java serde/src/java/org/apache/hadoop/hive/serde2/typeinfo/TypeInfoUtils.java index fd7c12a..9b85c65 100644 --- serde/src/java/org/apache/hadoop/hive/serde2/typeinfo/TypeInfoUtils.java +++ serde/src/java/org/apache/hadoop/hive/serde2/typeinfo/TypeInfoUtils.java @@ -66,7 +66,6 @@ // that were arbitrarily assigned in PrimitiveCategory work for our purposes. public static EnumMap numericTypes = new EnumMap(PrimitiveCategory.class); - static { registerNumericType(PrimitiveCategory.BYTE, 1); registerNumericType(PrimitiveCategory.SHORT, 2); @@ -78,6 +77,15 @@ registerNumericType(PrimitiveCategory.STRING, 8); } + public static List dateTypeList = new ArrayList(); + public static EnumMap dateTypes = + new EnumMap(PrimitiveCategory.class); + static { + registerDateType(PrimitiveCategory.DATE, 1); + registerDateType(PrimitiveCategory.TIMESTAMP, 2); + registerDateType(PrimitiveCategory.TIMESTAMPLOCALTZ, 3); + } + private TypeInfoUtils() { // prevent instantiation } @@ -900,6 +908,11 @@ public static synchronized void registerNumericType(PrimitiveCategory primitiveC numericTypes.put(primitiveCategory, level); } + public static synchronized void registerDateType(PrimitiveCategory primitiveCategory, int level) { + dateTypeList.add(primitiveCategory); + dateTypes.put(primitiveCategory, level); + } + /** * Test if it's implicitly convertible for data comparison. */