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..1285009 100644 --- ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java +++ ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java @@ -793,90 +793,69 @@ public static synchronized TypeInfo getCommonClassForComparison(TypeInfo a, Type if (a.equals(b)) { return a; } + + PrimitiveCategory pc = getPrimitiveCommonCategory(a, b); + if (pc != null) { + return getTypeInfoForPrimitiveCategory((PrimitiveTypeInfo)a, (PrimitiveTypeInfo)b, pc); + } + + return null; + } + + public static PrimitiveCategory getPrimitiveCommonCategory(TypeInfo a, TypeInfo b) { if (a.getCategory() != Category.PRIMITIVE || b.getCategory() != Category.PRIMITIVE) { return null; } + PrimitiveCategory pcA = ((PrimitiveTypeInfo)a).getPrimitiveCategory(); PrimitiveCategory pcB = ((PrimitiveTypeInfo)b).getPrimitiveCategory(); if (pcA == pcB) { - // Same primitive category but different qualifiers. - // Rely on getTypeInfoForPrimitiveCategory() to sort out the type params. - return getTypeInfoForPrimitiveCategory((PrimitiveTypeInfo)a, (PrimitiveTypeInfo)b, pcA); + // Same primitive category + return pcA; } PrimitiveGrouping pgA = PrimitiveObjectInspectorUtils.getPrimitiveGrouping(pcA); PrimitiveGrouping pgB = PrimitiveObjectInspectorUtils.getPrimitiveGrouping(pcB); - 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; + // 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; } } - // handle string types properly - if (pgA == PrimitiveGrouping.STRING_GROUP && pgB == PrimitiveGrouping.STRING_GROUP) { - // Compare as strings. Char comparison semantics may be different if/when implemented. - return getTypeInfoForPrimitiveCategory( - (PrimitiveTypeInfo)a, (PrimitiveTypeInfo)b,PrimitiveCategory.STRING); - } - // timestamp/date is higher precedence than String_GROUP + // Handle date-string comparisons if (pgA == PrimitiveGrouping.STRING_GROUP && pgB == PrimitiveGrouping.DATE_GROUP) { - return b; + return pcB; } - // date/timestamp is higher precedence than String_GROUP if (pgB == PrimitiveGrouping.STRING_GROUP && pgA == PrimitiveGrouping.DATE_GROUP) { - return a; + return pcA; } // Another special case, because timestamp is not implicitly convertible to numeric types. if ((pgA == PrimitiveGrouping.NUMERIC_GROUP || pgB == PrimitiveGrouping.NUMERIC_GROUP) && (pcA == PrimitiveCategory.TIMESTAMP || pcB == PrimitiveCategory.TIMESTAMP)) { - return TypeInfoFactory.doubleTypeInfo; - } - - for (PrimitiveCategory t : TypeInfoUtils.numericTypeList) { - if (TypeInfoUtils.implicitConvertible(pcA, t) - && TypeInfoUtils.implicitConvertible(pcB, t)) { - return getTypeInfoForPrimitiveCategory((PrimitiveTypeInfo)a, (PrimitiveTypeInfo)b, t); - } + return PrimitiveCategory.DOUBLE; } + // We could not find a common category, return null return null; } - public static PrimitiveCategory getPrimitiveCommonCategory(TypeInfo a, TypeInfo b) { - if (a.getCategory() != Category.PRIMITIVE || b.getCategory() != Category.PRIMITIVE) { - return null; - } - - PrimitiveCategory pcA = ((PrimitiveTypeInfo)a).getPrimitiveCategory(); - PrimitiveCategory pcB = ((PrimitiveTypeInfo)b).getPrimitiveCategory(); - - 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 (pgB == PrimitiveGrouping.DATE_GROUP && pgA == PrimitiveGrouping.STRING_GROUP) { - return PrimitiveCategory.STRING; - } - 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; - } - - return (ai > bi) ? pcA : pcB; - } - /** * Find a common class that objects of both TypeInfo a and TypeInfo b can * convert to. This is used for places other than comparison. 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 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. */