You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ha...@apache.org on 2014/09/12 02:37:15 UTC

svn commit: r1624431 - /hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java

Author: hashutosh
Date: Fri Sep 12 00:37:14 2014
New Revision: 1624431

URL: http://svn.apache.org/r1624431
Log:
HIVE-8064 : CBO: decimal support is broken for some corner cases (Sergey Shelukhin via Ashutosh Chauhan)

Modified:
    hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java

Modified: hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java
URL: http://svn.apache.org/viewvc/hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java?rev=1624431&r1=1624430&r2=1624431&view=diff
==============================================================================
--- hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java (original)
+++ hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/optimizer/optiq/translator/RexNodeConverter.java Fri Sep 12 00:37:14 2014
@@ -18,6 +18,7 @@
 package org.apache.hadoop.hive.ql.optimizer.optiq.translator;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -29,6 +30,8 @@ import java.util.Map;
 
 import net.hydromatic.avatica.ByteString;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hive.common.type.Decimal128;
 import org.apache.hadoop.hive.common.type.HiveChar;
 import org.apache.hadoop.hive.common.type.HiveDecimal;
@@ -69,12 +72,14 @@ import org.eigenbase.rex.RexNode;
 import org.eigenbase.rex.RexUtil;
 import org.eigenbase.sql.SqlOperator;
 import org.eigenbase.sql.fun.SqlCastFunction;
+import org.eigenbase.sql.type.SqlTypeName;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
 import com.google.common.collect.ImmutableMap;
 
 public class RexNodeConverter {
+  private static final Log LOG = LogFactory.getLog(RexNodeConverter.class);
 
   private static class InputCtx {
     private final RelDataType                   m_optiqInpDataType;
@@ -110,11 +115,8 @@ public class RexNodeConverter {
 
   public RexNode convert(ExprNodeDesc expr) throws SemanticException {
     if (expr instanceof ExprNodeNullDesc) {
-      return m_cluster.getRexBuilder().makeNullLiteral(
-          TypeConverter.convert(expr.getTypeInfo(), m_cluster.getRexBuilder().getTypeFactory())
-              .getSqlTypeName());
-    }
-    if (expr instanceof ExprNodeGenericFuncDesc) {
+      return createNullLiteral(expr);
+    } else if (expr instanceof ExprNodeGenericFuncDesc) {
       return convert((ExprNodeGenericFuncDesc) expr);
     } else if (expr instanceof ExprNodeConstantDesc) {
       return convert((ExprNodeConstantDesc) expr);
@@ -273,7 +275,10 @@ public class RexNodeConverter {
         ic.m_optiqInpDataType.getFieldList().get(pos).getType(), pos + ic.m_offsetInOptiqSchema);
   }
 
-  protected RexNode convert(ExprNodeConstantDesc literal) {
+  private static final BigInteger MIN_LONG_BI = BigInteger.valueOf(Long.MIN_VALUE),
+      MAX_LONG_BI = BigInteger.valueOf(Long.MAX_VALUE);
+
+  protected RexNode convert(ExprNodeConstantDesc literal) throws OptiqSemanticException {
     RexBuilder rexBuilder = m_cluster.getRexBuilder();
     RelDataTypeFactory dtFactory = rexBuilder.getTypeFactory();
     PrimitiveTypeInfo hiveType = (PrimitiveTypeInfo) literal.getTypeInfo();
@@ -282,8 +287,8 @@ public class RexNodeConverter {
     PrimitiveCategory hiveTypeCategory = hiveType.getPrimitiveCategory();
 
     ConstantObjectInspector coi = literal.getWritableObjectInspector();
-    Object value = ObjectInspectorUtils.copyToStandardJavaObject(literal
-        .getWritableObjectInspector().getWritableConstantValue(), coi);
+    Object value = ObjectInspectorUtils.copyToStandardJavaObject(
+        coi.getWritableConstantValue(), coi);
 
     RexNode optiqLiteral = null;
     // TODO: Verify if we need to use ConstantObjectInspector to unwrap data
@@ -307,11 +312,32 @@ public class RexNodeConverter {
       break;
     // TODO: is Decimal an exact numeric or approximate numeric?
     case DECIMAL:
-      if (value instanceof HiveDecimal)
+      if (value instanceof HiveDecimal) {
         value = ((HiveDecimal) value).bigDecimalValue();
-      if (value instanceof Decimal128)
+      } else if (value instanceof Decimal128) {
         value = ((Decimal128) value).toBigDecimal();
-      optiqLiteral = rexBuilder.makeExactLiteral((BigDecimal) value);
+      }
+      if (value == null) {
+        // We have found an invalid decimal value while enforcing precision and scale. Ideally,
+        // we would replace it with null here, which is what Hive does. However, we need to plumb
+        // this thru up somehow, because otherwise having different expression type in AST causes
+        // the plan generation to fail after CBO, probably due to some residual state in SA/QB.
+        // For now, we will not run CBO in the presence of invalid decimal literals.
+        throw new OptiqSemanticException("Expression "
+          + literal.getExprString() + " is not a valid decimal");
+        // TODO: return createNullLiteral(literal);
+      }
+      BigDecimal bd = (BigDecimal)value;
+      BigInteger unscaled = bd.unscaledValue();
+      if (unscaled.compareTo(MIN_LONG_BI) >= 0 && unscaled.compareTo(MAX_LONG_BI) <= 0) {
+        optiqLiteral = rexBuilder.makeExactLiteral(bd);
+      } else {
+        // CBO doesn't support unlimited precision decimals. In practice, this will work...
+        // An alternative would be to throw CboSemanticException and fall back to no CBO.
+        RelDataType relType = m_cluster.getTypeFactory().createSqlType(
+                SqlTypeName.DECIMAL, bd.scale(), unscaled.toString().length());
+        optiqLiteral = rexBuilder.makeExactLiteral(bd, relType);
+      }
       break;
     case FLOAT:
       optiqLiteral = rexBuilder.makeApproxLiteral(new BigDecimal((Float) value), optiqDataType);
@@ -351,6 +377,11 @@ public class RexNodeConverter {
     return optiqLiteral;
   }
 
+  private RexNode createNullLiteral(ExprNodeDesc expr) throws OptiqSemanticException {
+    return m_cluster.getRexBuilder().makeNullLiteral(TypeConverter.convert(
+        expr.getTypeInfo(), m_cluster.getTypeFactory()).getSqlTypeName());
+  }
+
   public static RexNode convert(RelOptCluster cluster, ExprNodeDesc joinCondnExprNode,
       List<RelNode> inputRels, LinkedHashMap<RelNode, RowResolver> relToHiveRR,
       Map<RelNode, ImmutableMap<String, Integer>> relToHiveColNameOptiqPosMap, boolean flattenExpr)