diff --git ql/src/java/org/apache/hadoop/hive/ql/io/sarg/ConvertAstToSearchArg.java ql/src/java/org/apache/hadoop/hive/ql/io/sarg/ConvertAstToSearchArg.java index 51b1ac6..5174ef6 100644 --- ql/src/java/org/apache/hadoop/hive/ql/io/sarg/ConvertAstToSearchArg.java +++ ql/src/java/org/apache/hadoop/hive/ql/io/sarg/ConvertAstToSearchArg.java @@ -25,6 +25,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; + import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.common.type.HiveChar; @@ -55,6 +56,7 @@ import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; +import org.apache.hadoop.hive.ql.io.sarg.PredicateLeaf.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,6 +68,27 @@ private final SearchArgument.Builder builder; private final Configuration conf; + /* + * Create a new type for handling precision conversions from Decimal -> Double/Float + * + * The type is only relevant to boxLiteral and all other functions treat it identically. + */ + private static enum BoxType { + LONG(PredicateLeaf.Type.LONG), // all of the integer types + FLOAT(PredicateLeaf.Type.FLOAT), // float + DOUBLE(PredicateLeaf.Type.FLOAT), // double + STRING(PredicateLeaf.Type.STRING), // string, char, varchar + DATE(PredicateLeaf.Type.DATE), + DECIMAL(PredicateLeaf.Type.DECIMAL), + TIMESTAMP(PredicateLeaf.Type.TIMESTAMP), + BOOLEAN(PredicateLeaf.Type.BOOLEAN); + + public final PredicateLeaf.Type type; + BoxType(PredicateLeaf.Type type) { + this.type = type; + } + } + /** * Builds the expression and leaf list from the original predicate. * @param expression the expression to translate. @@ -89,7 +112,7 @@ public SearchArgument buildSearchArgument() { * @param expr the expression to get the type of * @return int, string, or float or null if we don't know the type */ - private static PredicateLeaf.Type getType(ExprNodeDesc expr) { + private static BoxType getType(ExprNodeDesc expr) { TypeInfo type = expr.getTypeInfo(); if (type.getCategory() == ObjectInspector.Category.PRIMITIVE) { switch (((PrimitiveTypeInfo) type).getPrimitiveCategory()) { @@ -97,22 +120,23 @@ public SearchArgument buildSearchArgument() { case SHORT: case INT: case LONG: - return PredicateLeaf.Type.LONG; + return BoxType.LONG; case CHAR: case VARCHAR: case STRING: - return PredicateLeaf.Type.STRING; + return BoxType.STRING; case FLOAT: + return BoxType.FLOAT; case DOUBLE: - return PredicateLeaf.Type.FLOAT; + return BoxType.DOUBLE; case DATE: - return PredicateLeaf.Type.DATE; + return BoxType.DATE; case TIMESTAMP: - return PredicateLeaf.Type.TIMESTAMP; + return BoxType.TIMESTAMP; case DECIMAL: - return PredicateLeaf.Type.DECIMAL; + return BoxType.DECIMAL; case BOOLEAN: - return PredicateLeaf.Type.BOOLEAN; + return BoxType.BOOLEAN; default: } } @@ -140,12 +164,12 @@ private static String getColumnName(ExprNodeGenericFuncDesc expr, } private static Object boxLiteral(ExprNodeConstantDesc constantDesc, - PredicateLeaf.Type type) { + BoxType boxType) { Object lit = constantDesc.getValue(); if (lit == null) { return null; } - switch (type) { + switch (boxType) { case LONG: if (lit instanceof HiveDecimal) { HiveDecimal dec = (HiveDecimal) lit; @@ -163,13 +187,24 @@ private static Object boxLiteral(ExprNodeConstantDesc constantDesc, } else { return lit.toString(); } + case DOUBLE: + final Number dbl; + if (lit instanceof HiveDecimal) { + // HiveDecimal -> Number -> Double + dbl = ((HiveDecimal) lit).doubleValue(); + } else { + dbl = ((Number) lit); + } + return dbl.doubleValue(); case FLOAT: + final Number fl; if (lit instanceof HiveDecimal) { - // HiveDecimal -> Float -> Number -> Double - return ((Number)((HiveDecimal) lit).floatValue()).doubleValue(); + // HiveDecimal -> Float -> Number + fl = ((Number)((HiveDecimal) lit).floatValue()); } else { - return ((Number) lit).doubleValue(); + fl = ((Number) lit); } + return fl.doubleValue(); case TIMESTAMP: return Timestamp.valueOf(lit.toString()); case DATE: @@ -179,25 +214,25 @@ private static Object boxLiteral(ExprNodeConstantDesc constantDesc, case BOOLEAN: return lit; default: - throw new IllegalArgumentException("Unknown literal " + type); + throw new IllegalArgumentException("Unknown literal " + boxType); } } /** * Find the child that is the literal. * @param expr the parent node to check - * @param type the type of the expression + * @param boxType the type of the expression * @return the literal boxed if found or null */ private static Object findLiteral(Configuration conf, ExprNodeGenericFuncDesc expr, - PredicateLeaf.Type type) { + final BoxType boxType) { List children = expr.getChildren(); if (children.size() != 2) { return null; } Object result = null; for(ExprNodeDesc child: children) { - Object currentResult = getLiteral(conf, child, type); + Object currentResult = getLiteral(conf, child, boxType); if (currentResult != null) { // Both children in the expression should not be literal if (result != null) { @@ -209,9 +244,9 @@ private static Object findLiteral(Configuration conf, ExprNodeGenericFuncDesc ex return result; } - private static Object getLiteral(Configuration conf, ExprNodeDesc child, PredicateLeaf.Type type) { + private static Object getLiteral(Configuration conf, ExprNodeDesc child, BoxType boxType) { if (child instanceof ExprNodeConstantDesc) { - return boxLiteral((ExprNodeConstantDesc) child, type); + return boxLiteral((ExprNodeConstantDesc) child, boxType); } else if (child instanceof ExprNodeDynamicValueDesc) { LiteralDelegate value = ((ExprNodeDynamicValueDesc) child).getDynamicValue(); value.setConf(conf); @@ -228,15 +263,15 @@ private static Object getLiteral(Configuration conf, ExprNodeDesc child, Predica * @return the boxed literal if found otherwise null */ private static Object getLiteral(Configuration conf, ExprNodeGenericFuncDesc expr, - PredicateLeaf.Type type, + BoxType boxType, int position) { List children = expr.getChildren(); ExprNodeDesc child = children.get(position); - return getLiteral(conf, child, type); + return getLiteral(conf, child, boxType); } private static Object[] getLiteralList(ExprNodeGenericFuncDesc expr, - PredicateLeaf.Type type, + BoxType boxType, int start) { List children = expr.getChildren(); Object[] result = new Object[children.size() - start]; @@ -245,7 +280,7 @@ private static Object getLiteral(Configuration conf, ExprNodeGenericFuncDesc exp int posn = 0; for(ExprNodeDesc child: children.subList(start, children.size())) { if (child instanceof ExprNodeConstantDesc) { - result[posn++] = boxLiteral((ExprNodeConstantDesc) child, type); + result[posn++] = boxLiteral((ExprNodeConstantDesc) child, boxType); } else { // if we get some non-literals, we need to punt return null; @@ -262,8 +297,8 @@ private void createLeaf(PredicateLeaf.Operator operator, builder.literal(SearchArgument.TruthValue.YES_NO_NULL); return; } - PredicateLeaf.Type type = getType(expression.getChildren().get(variable)); - if (type == null) { + BoxType boxType = getType(expression.getChildren().get(variable)); + if (boxType == null) { builder.literal(SearchArgument.TruthValue.YES_NO_NULL); return; } @@ -286,28 +321,28 @@ private void createLeaf(PredicateLeaf.Operator operator, try { switch (operator) { case IS_NULL: - builder.isNull(columnName, type); + builder.isNull(columnName, boxType.type); break; case EQUALS: - builder.equals(columnName, type, findLiteral(conf, expression, type)); + builder.equals(columnName, boxType.type, findLiteral(conf, expression, boxType)); break; case NULL_SAFE_EQUALS: - builder.nullSafeEquals(columnName, type, findLiteral(conf, expression, type)); + builder.nullSafeEquals(columnName, boxType.type, findLiteral(conf, expression, boxType)); break; case LESS_THAN: - builder.lessThan(columnName, type, findLiteral(conf, expression, type)); + builder.lessThan(columnName, boxType.type, findLiteral(conf, expression, boxType)); break; case LESS_THAN_EQUALS: - builder.lessThanEquals(columnName, type, findLiteral(conf, expression, type)); + builder.lessThanEquals(columnName, boxType.type, findLiteral(conf, expression, boxType)); break; case IN: - builder.in(columnName, type, - getLiteralList(expression, type, variable + 1)); + builder.in(columnName, boxType.type, + getLiteralList(expression, boxType, variable + 1)); break; case BETWEEN: - builder.between(columnName, type, - getLiteral(conf, expression, type, variable + 1), - getLiteral(conf, expression, type, variable + 2)); + builder.between(columnName, boxType.type, + getLiteral(conf, expression, boxType, variable + 1), + getLiteral(conf, expression, boxType, variable + 2)); break; } } catch (Exception e) {