You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by br...@apache.org on 2013/11/04 22:32:20 UTC

svn commit: r1538778 - in /hive/trunk/ql/src: java/org/apache/hadoop/hive/ql/exec/ java/org/apache/hadoop/hive/ql/exec/vector/expressions/ java/org/apache/hadoop/hive/ql/optimizer/physical/ java/org/apache/hadoop/hive/ql/udf/ java/org/apache/hadoop/hiv...

Author: brock
Date: Mon Nov  4 21:32:20 2013
New Revision: 1538778

URL: http://svn.apache.org/r1538778
Log:
HIVE-4523 - round() function with specified decimal places not consistent with mysql (Xuefu Zhang via Brock Noland)

Added:
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFRound.java
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/RoundUtils.java
    hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFRound.java
Removed:
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/UDFRound.java
    hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/TestUDFRound.java
Modified:
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/RoundWithNumDigitsDoubleToDouble.java
    hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java
    hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/TestVectorizationContext.java
    hive/trunk/ql/src/test/queries/clientpositive/udf_round.q
    hive/trunk/ql/src/test/results/clientpositive/decimal_udf.q.out
    hive/trunk/ql/src/test/results/clientpositive/udf_round.q.out
    hive/trunk/ql/src/test/results/compiler/plan/udf4.q.xml

Modified: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java (original)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java Mon Nov  4 21:32:20 2013
@@ -105,7 +105,6 @@ import org.apache.hadoop.hive.ql.udf.UDF
 import org.apache.hadoop.hive.ql.udf.UDFRegExpReplace;
 import org.apache.hadoop.hive.ql.udf.UDFRepeat;
 import org.apache.hadoop.hive.ql.udf.UDFReverse;
-import org.apache.hadoop.hive.ql.udf.UDFRound;
 import org.apache.hadoop.hive.ql.udf.UDFRpad;
 import org.apache.hadoop.hive.ql.udf.UDFSecond;
 import org.apache.hadoop.hive.ql.udf.UDFSign;
@@ -203,7 +202,7 @@ public final class FunctionRegistry {
 
     registerGenericUDF("size", GenericUDFSize.class);
 
-    registerUDF("round", UDFRound.class, false);
+    registerGenericUDF("round", GenericUDFRound.class);
     registerUDF("floor", UDFFloor.class, false);
     registerUDF("sqrt", UDFSqrt.class, false);
     registerUDF("ceil", UDFCeil.class, false);

Modified: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/RoundWithNumDigitsDoubleToDouble.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/RoundWithNumDigitsDoubleToDouble.java?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/RoundWithNumDigitsDoubleToDouble.java (original)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/RoundWithNumDigitsDoubleToDouble.java Mon Nov  4 21:32:20 2013
@@ -19,8 +19,7 @@
 package org.apache.hadoop.hive.ql.exec.vector.expressions;
 
 import org.apache.hadoop.hive.ql.exec.vector.VectorExpressionDescriptor;
-import org.apache.hadoop.hive.ql.udf.UDFRound;
-import org.apache.hadoop.hive.serde2.io.DoubleWritable;
+import org.apache.hadoop.hive.ql.udf.generic.RoundUtils;
 import org.apache.hadoop.io.IntWritable;
 
 // Vectorized implementation of ROUND(Col, N) function
@@ -29,28 +28,21 @@ public class RoundWithNumDigitsDoubleToD
   private static final long serialVersionUID = 1L;
 
   private IntWritable decimalPlaces;
-  private transient UDFRound roundFunc;
-  private transient DoubleWritable dw;
 
   public RoundWithNumDigitsDoubleToDouble(int colNum, long scalarVal, int outputColumn) {
     super(colNum, outputColumn);
     this.decimalPlaces = new IntWritable();
-    roundFunc = new UDFRound();
-    dw = new DoubleWritable();
     decimalPlaces.set((int) scalarVal);
   }
 
   public RoundWithNumDigitsDoubleToDouble() {
     super();
-    dw = new DoubleWritable();
-    roundFunc = new UDFRound();
   }
 
   // Round to the specified number of decimal places using the standard Hive round function.
   @Override
   public double func(double d) {
-    dw.set(d);
-    return roundFunc.evaluate(dw, decimalPlaces).get();
+    return RoundUtils.round(d, decimalPlaces.get());
   }
 
   void setDecimalPlaces(IntWritable decimalPlaces) {
@@ -61,14 +53,6 @@ public class RoundWithNumDigitsDoubleToD
     return this.decimalPlaces;
   }
 
-  void setRoundFunc(UDFRound roundFunc) {
-    this.roundFunc = roundFunc;
-  }
-
-  UDFRound getRoundFunc() {
-    return this.roundFunc;
-  }
-
   @Override
   public void setArg(long l) {
     this.decimalPlaces.set((int) l);

Modified: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java (original)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java Mon Nov  4 21:32:20 2013
@@ -73,6 +73,7 @@ import org.apache.hadoop.hive.ql.udf.gen
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotNull;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNull;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPOr;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDFRound;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFTimestamp;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFToUnixTimeStamp;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFUpper;
@@ -158,7 +159,7 @@ public class Vectorizer implements Physi
     supportedGenericUDFs.add(UDFLog.class);
     supportedGenericUDFs.add(UDFPower.class);
     supportedGenericUDFs.add(UDFPosMod.class);
-    supportedGenericUDFs.add(UDFRound.class);
+    supportedGenericUDFs.add(GenericUDFRound.class);
     supportedGenericUDFs.add(UDFSqrt.class);
     supportedGenericUDFs.add(UDFSign.class);
     supportedGenericUDFs.add(UDFRand.class);

Added: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFRound.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFRound.java?rev=1538778&view=auto
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFRound.java (added)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFRound.java Mon Nov  4 21:32:20 2013
@@ -0,0 +1,267 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.ql.udf.generic;
+
+import org.apache.hadoop.hive.common.type.HiveDecimal;
+import org.apache.hadoop.hive.ql.exec.Description;
+import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
+import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
+import org.apache.hadoop.hive.ql.exec.vector.VectorizedExpressions;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.RoundWithNumDigitsDoubleToDouble;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.FuncRoundDoubleToDouble;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+import org.apache.hadoop.hive.serde2.io.ByteWritable;
+import org.apache.hadoop.hive.serde2.io.DoubleWritable;
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
+import org.apache.hadoop.hive.serde2.io.ShortWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.Converter;
+import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableConstantByteObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableConstantIntObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableConstantLongObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableConstantShortObjectInspector;
+import org.apache.hadoop.hive.serde2.typeinfo.DecimalTypeInfo;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+import org.apache.hadoop.io.FloatWritable;
+import org.apache.hadoop.io.IntWritable;
+import org.apache.hadoop.io.LongWritable;
+
+/**
+ * Note: rounding function permits rounding off integer digits in decimal numbers, which essentially
+ * downgrades the scale to negative territory. However, Hive decimal only allow non-negative scales.
+ * This can cause confusion, for example, when a decimal number 1234.567 of type decimal(7,3) is
+ * rounded with -2 scale, which produces a decimal number, 1200. The type of the output is
+ * decimal(5,0), which does not exactly represents what the number means. Thus, user should
+ * be aware of this, and use negative rounding for decimal with caution. However, Hive is in line
+ * with the behavior that MYSQL demonstrates.
+ *
+ * At a certain point, we should probably support negative scale for decimal type.
+ *
+ * GenericUDFRound.
+ *
+ */
+@Description(name = "round",
+  value = "_FUNC_(x[, d]) - round x to d decimal places",
+  extended = "Example:\n"
+    + "  > SELECT _FUNC_(12.3456, 1) FROM src LIMIT 1;\n" + "  12.3'")
+@VectorizedExpressions({FuncRoundDoubleToDouble.class, RoundWithNumDigitsDoubleToDouble.class})
+public class GenericUDFRound extends GenericUDF {
+  private transient PrimitiveObjectInspector inputOI;
+  private int scale = 0;
+
+  private transient PrimitiveCategory inputType;
+  private transient Converter converterFromString;
+
+  @Override
+  public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
+    if (arguments.length < 1 || arguments.length > 2) {
+      throw new UDFArgumentLengthException(
+          "ROUND requires one or two argument, got " + arguments.length);
+    }
+
+    inputOI = (PrimitiveObjectInspector) arguments[0];
+    if (inputOI.getCategory() != Category.PRIMITIVE) {
+      throw new UDFArgumentException(
+          "ROUND input only takes primitive types, got " + inputOI.getTypeName());
+    }
+
+    if (arguments.length == 2) {
+      PrimitiveObjectInspector scaleOI = (PrimitiveObjectInspector) arguments[1];
+      switch (scaleOI.getPrimitiveCategory()) {
+      case VOID:
+        break;
+      case BYTE:
+        if (!(scaleOI instanceof WritableConstantByteObjectInspector)) {
+          throw new UDFArgumentException("ROUND second argument only takes constant");
+        }
+        scale = ((WritableConstantByteObjectInspector)scaleOI).getWritableConstantValue().get();
+        break;
+      case SHORT:
+        if (!(scaleOI instanceof WritableConstantShortObjectInspector)) {
+          throw new UDFArgumentException("ROUND second argument only takes constant");
+        }
+        scale = ((WritableConstantShortObjectInspector)scaleOI).getWritableConstantValue().get();
+        break;
+      case INT:
+        if (!(scaleOI instanceof WritableConstantIntObjectInspector)) {
+          throw new UDFArgumentException("ROUND second argument only takes constant");
+        }
+        scale = ((WritableConstantIntObjectInspector)scaleOI).getWritableConstantValue().get();
+        break;
+      case LONG:
+        if (!(scaleOI instanceof WritableConstantLongObjectInspector)) {
+          throw new UDFArgumentException("ROUND second argument only takes constant");
+        }
+        long l = ((WritableConstantLongObjectInspector)scaleOI).getWritableConstantValue().get();
+        if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
+          throw new UDFArgumentException("ROUND scale argument out of allowed range");
+        }
+        scale = (int)l;
+        break;
+      default:
+        throw new UDFArgumentException("ROUND second argument only takes integer constant");
+      }
+    }
+
+    inputType = inputOI.getPrimitiveCategory();
+    ObjectInspector outputOI = null;
+    switch (inputType) {
+    case DECIMAL:
+      DecimalTypeInfo inputTypeInfo = (DecimalTypeInfo) inputOI.getTypeInfo();
+      DecimalTypeInfo typeInfo = getOutputTypeInfo(inputTypeInfo, scale);
+      outputOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(typeInfo);
+      break;
+    case VOID:
+    case BYTE:
+    case SHORT:
+    case INT:
+    case LONG:
+    case FLOAT:
+    case DOUBLE:
+      outputOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(inputType);
+      break;
+    case STRING:
+    case VARCHAR:
+      outputOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(PrimitiveCategory.DOUBLE);
+      converterFromString = ObjectInspectorConverters.getConverter(inputOI, outputOI);
+      break;
+    default:
+      throw new UDFArgumentException("Only numeric data types are allowed for ROUND function. Got " +
+          inputType.name());
+    }
+
+    return outputOI;
+  }
+
+  private static DecimalTypeInfo getOutputTypeInfo(DecimalTypeInfo inputTypeInfo, int dec) {
+    int prec = inputTypeInfo.precision();
+    int scale = inputTypeInfo.scale();
+    int intParts = prec - scale;
+
+    // If we are rounding, we may introduce one more integer digit.
+    int newIntParts = dec < scale ? intParts + 1 : intParts;
+
+    int newScale = dec < 0 ? 0 : Math.min(dec, HiveDecimal.MAX_SCALE);
+
+    int newPrec = Math.min(newIntParts + newScale, HiveDecimal.MAX_PRECISION);
+
+    return TypeInfoFactory.getDecimalTypeInfo(newPrec, newScale);
+  }
+
+  @Override
+  public Object evaluate(DeferredObject[] arguments) throws HiveException {
+    if (arguments.length == 2 && (arguments[1] == null || arguments[1].get() == null)) {
+      return null;
+    }
+
+    if (arguments[0] == null) {
+      return null;
+    }
+
+    Object input = arguments[0].get();
+    if (input == null) {
+      return null;
+    }
+
+    switch (inputType) {
+    case VOID:
+      return null;
+    case DECIMAL:
+      HiveDecimalWritable decimalWritable = (HiveDecimalWritable) inputOI.getPrimitiveWritableObject(input);
+      HiveDecimal dec = RoundUtils.round(decimalWritable.getHiveDecimal(), scale);
+      if (dec == null) {
+        return null;
+      }
+      return new HiveDecimalWritable(dec);
+    case BYTE:
+      ByteWritable byteWritable = (ByteWritable)inputOI.getPrimitiveWritableObject(input);
+      if (scale >= 0) {
+        return byteWritable;
+      } else {
+        return new ByteWritable((byte)RoundUtils.round(byteWritable.get(), scale));
+      }
+    case SHORT:
+      ShortWritable shortWritable = (ShortWritable)inputOI.getPrimitiveWritableObject(input);
+      if (scale >= 0) {
+        return shortWritable;
+      } else {
+        return new ShortWritable((short)RoundUtils.round(shortWritable.get(), scale));
+      }
+    case INT:
+      IntWritable intWritable = (IntWritable)inputOI.getPrimitiveWritableObject(input);
+      if (scale >= 0) {
+        return intWritable;
+      } else {
+        return new IntWritable((int)RoundUtils.round(intWritable.get(), scale));
+      }
+    case LONG:
+      LongWritable longWritable = (LongWritable)inputOI.getPrimitiveWritableObject(input);
+      if (scale >= 0) {
+        return longWritable;
+      } else {
+        return new LongWritable(RoundUtils.round(longWritable.get(), scale));
+      }
+    case FLOAT:
+      float f = ((FloatWritable)inputOI.getPrimitiveWritableObject(input)).get();
+      return new FloatWritable((float)RoundUtils.round(f, scale));
+     case DOUBLE:
+       return round(((DoubleWritable)inputOI.getPrimitiveWritableObject(input)), scale);
+    case STRING:
+     case VARCHAR:
+       DoubleWritable doubleValue = (DoubleWritable) converterFromString.convert(input);
+       if (doubleValue == null) {
+         return null;
+       }
+       return round(doubleValue, scale);
+     default:
+       throw new UDFArgumentException("Only numeric data types are allowed for ROUND function. Got " +
+           inputType.name());
+    }
+  }
+
+  private static DoubleWritable round(DoubleWritable input, int scale) {
+    double d = input.get();
+    if (Double.isNaN(d) || Double.isInfinite(d)) {
+      return new DoubleWritable(d);
+    } else {
+      return new DoubleWritable(RoundUtils.round(d, scale));
+    }
+  }
+
+  @Override
+  public String getDisplayString(String[] children) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("round(");
+    if (children.length > 0) {
+      sb.append(children[0]);
+      for (int i = 1; i < children.length; i++) {
+        sb.append(", ");
+        sb.append(children[i]);
+      }
+    }
+    sb.append(")");
+    return sb.toString();
+  }
+
+}

Added: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/RoundUtils.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/RoundUtils.java?rev=1538778&view=auto
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/RoundUtils.java (added)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/RoundUtils.java Mon Nov  4 21:32:20 2013
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.ql.udf.generic;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+import org.apache.hadoop.hive.common.type.HiveDecimal;
+
+/**
+ * Utility class for generic round UDF.
+ *
+ */
+public class RoundUtils {
+
+  private RoundUtils() {
+  }
+
+  /**
+   * Rounding a double is approximate, as the double value itself is approximate.
+   * A double literal, such as 3.15, may not be represented internally exactly as
+   * 3.15. thus, the rounding value of it can be off on the surface. For accurate
+   * rounding, consider using decimal type.
+   *
+   * @param input input value
+   * @param scale decimal place
+   * @return rounded value
+   */
+  public static double round(double input, int scale) {
+    if (Double.isNaN(input) || Double.isInfinite(input)) {
+      return input;
+    }
+    return BigDecimal.valueOf(input).setScale(scale, RoundingMode.HALF_UP).doubleValue();
+  }
+
+  public static long round(long input, int scale) {
+    return BigDecimal.valueOf(input).setScale(scale, RoundingMode.HALF_UP).longValue();
+  }
+
+  public static HiveDecimal round(HiveDecimal input, int scale) {
+    return input.setScale(scale, HiveDecimal.ROUND_HALF_UP);
+  }
+
+}

Modified: hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/TestVectorizationContext.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/TestVectorizationContext.java?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/TestVectorizationContext.java (original)
+++ hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/exec/vector/TestVectorizationContext.java Mon Nov  4 21:32:20 2013
@@ -28,7 +28,27 @@ import java.util.Map;
 
 import junit.framework.Assert;
 
-import org.apache.hadoop.hive.ql.exec.vector.expressions.*;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.ColAndCol;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.ColOrCol;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.FilterExprAndExpr;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.FilterExprOrExpr;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.FuncLogWithBaseDoubleToDouble;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.FuncLogWithBaseLongToDouble;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.FuncPowerDoubleToDouble;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.IsNotNull;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.IsNull;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.NotCol;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.RoundWithNumDigitsDoubleToDouble;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.SelectColumnIsFalse;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.SelectColumnIsNotNull;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.SelectColumnIsNull;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.SelectColumnIsTrue;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.StringLTrim;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.StringLower;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.StringUpper;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.VectorExpression;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.VectorUDFUnixTimeStampLong;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.VectorUDFYearLong;
 import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.DoubleColUnaryMinus;
 import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.FilterDoubleColLessDoubleScalar;
 import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.FilterDoubleColumnBetween;
@@ -59,7 +79,6 @@ import org.apache.hadoop.hive.ql.plan.Ex
 import org.apache.hadoop.hive.ql.plan.ExprNodeConstantDesc;
 import org.apache.hadoop.hive.ql.plan.ExprNodeDesc;
 import org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc;
-import org.apache.hadoop.hive.ql.plan.api.OperatorType;
 import org.apache.hadoop.hive.ql.udf.UDFLTrim;
 import org.apache.hadoop.hive.ql.udf.UDFLog;
 import org.apache.hadoop.hive.ql.udf.UDFOPMinus;
@@ -68,7 +87,6 @@ import org.apache.hadoop.hive.ql.udf.UDF
 import org.apache.hadoop.hive.ql.udf.UDFOPNegative;
 import org.apache.hadoop.hive.ql.udf.UDFOPPlus;
 import org.apache.hadoop.hive.ql.udf.UDFPower;
-import org.apache.hadoop.hive.ql.udf.UDFRound;
 import org.apache.hadoop.hive.ql.udf.UDFSin;
 import org.apache.hadoop.hive.ql.udf.UDFYear;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
@@ -83,6 +101,7 @@ import org.apache.hadoop.hive.ql.udf.gen
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotNull;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNull;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPOr;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDFRound;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFToUnixTimeStamp;
 import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
 import org.junit.Test;
@@ -766,15 +785,14 @@ public class TestVectorizationContext {
     Assert.assertEquals(FuncSinDoubleToDouble.class, ve.getClass());
 
     // Round without digits
-    gudfBridge = new GenericUDFBridge("round", false, UDFRound.class.getName());
-    mathFuncExpr.setGenericUDF(gudfBridge);
+    GenericUDFRound udfRound = new GenericUDFRound();
+    mathFuncExpr.setGenericUDF(udfRound);
     mathFuncExpr.setChildren(children2);
     ve = vc.getVectorExpression(mathFuncExpr);
     Assert.assertEquals(FuncRoundDoubleToDouble.class, ve.getClass());
 
     // Round with digits
-    gudfBridge = new GenericUDFBridge("round", false, UDFRound.class.getName());
-    mathFuncExpr.setGenericUDF(gudfBridge);
+    mathFuncExpr.setGenericUDF(udfRound);
     children2.add(new ExprNodeConstantDesc(4));
     mathFuncExpr.setChildren(children2);
     ve = vc.getVectorExpression(mathFuncExpr);
@@ -829,8 +847,7 @@ public class TestVectorizationContext {
     Assert.assertTrue(4.5 == ((FuncPowerDoubleToDouble) ve).getPower());
 
     //Round with default decimal places
-    gudfBridge = new GenericUDFBridge("round", false, UDFRound.class.getName());
-    mathFuncExpr.setGenericUDF(gudfBridge);
+    mathFuncExpr.setGenericUDF(udfRound);
     children2.clear();
     children2.add(colDesc2);
     mathFuncExpr.setChildren(children2);

Added: hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFRound.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFRound.java?rev=1538778&view=auto
==============================================================================
--- hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFRound.java (added)
+++ hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFRound.java Mon Nov  4 21:32:20 2013
@@ -0,0 +1,153 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.ql.udf.generic;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.apache.hadoop.hive.common.type.HiveDecimal;
+import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
+import org.apache.hadoop.hive.ql.parse.TypeCheckProcFactory;
+import org.apache.hadoop.hive.ql.plan.ExprNodeConstantDesc;
+import org.apache.hadoop.hive.ql.plan.ExprNodeDesc;
+import org.apache.hadoop.hive.ql.testutil.BaseScalarUdfTest;
+import org.apache.hadoop.hive.ql.testutil.DataBuilder;
+import org.apache.hadoop.hive.ql.testutil.OperatorTestUtils;
+import org.apache.hadoop.hive.serde2.io.ByteWritable;
+import org.apache.hadoop.hive.serde2.io.DoubleWritable;
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
+import org.apache.hadoop.hive.serde2.io.ShortWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.InspectableObject;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
+import org.apache.hadoop.hive.serde2.typeinfo.DecimalTypeInfo;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+import org.apache.hadoop.io.FloatWritable;
+import org.apache.hadoop.io.IntWritable;
+import org.apache.hadoop.io.LongWritable;
+import org.junit.Test;
+
+public class TestGenericUDFRound extends BaseScalarUdfTest {
+  private static final String[] cols = {"s", "i", "d", "f", "b", "sh", "l", "dec"};
+
+  @Override
+  public InspectableObject[] getBaseTable() {
+    DataBuilder db = new DataBuilder();
+    db.setColumnNames(cols);
+    db.setColumnTypes(
+        PrimitiveObjectInspectorFactory.javaStringObjectInspector,
+        PrimitiveObjectInspectorFactory.javaIntObjectInspector,
+        PrimitiveObjectInspectorFactory.javaDoubleObjectInspector,
+        PrimitiveObjectInspectorFactory.javaFloatObjectInspector,
+        PrimitiveObjectInspectorFactory.javaByteObjectInspector,
+        PrimitiveObjectInspectorFactory.javaShortObjectInspector,
+        PrimitiveObjectInspectorFactory.javaLongObjectInspector,
+        PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(TypeInfoFactory.getDecimalTypeInfo(15, 5)));
+    db.addRow("one", 170, new Double("1.1"), new Float("32.1234"), new Byte("25"), new Short("1234"), 123456L, HiveDecimal.create("983.7235"));
+    db.addRow( "-234", null, null, new Float("0.347232"), new Byte("109"), new Short("551"), 923L, HiveDecimal.create("983723.005"));
+    db.addRow("454.45", 22345,  new Double("-23.00009"), new Float("-3.4"), new Byte("76"), new Short("2321"), 9232L, HiveDecimal.create("-932032.7"));
+    return db.createRows();
+  }
+
+  @Override
+  public InspectableObject[] getExpectedResult() {
+    DataBuilder db = new DataBuilder();
+    db.setColumnNames("_col1", "_col2", "_col3", "_col4", "_col5", "_col6", "_col7", "_col8");
+    db.setColumnTypes(PrimitiveObjectInspectorFactory.javaStringObjectInspector,
+        PrimitiveObjectInspectorFactory.writableIntObjectInspector,
+        PrimitiveObjectInspectorFactory.writableDoubleObjectInspector,
+        PrimitiveObjectInspectorFactory.writableFloatObjectInspector,
+        PrimitiveObjectInspectorFactory.writableByteObjectInspector,
+        PrimitiveObjectInspectorFactory.writableShortObjectInspector,
+        PrimitiveObjectInspectorFactory.writableLongObjectInspector,
+        PrimitiveObjectInspectorFactory.writableHiveDecimalObjectInspector);
+    db.addRow(null, new IntWritable(170), new DoubleWritable(1.1), new FloatWritable(32f),
+        new ByteWritable((byte)0), new ShortWritable((short)1234), new LongWritable(123500L), new HiveDecimalWritable(HiveDecimal.create("983.724")));
+    db.addRow(new DoubleWritable(-200), null, null, new FloatWritable(0f),
+        new ByteWritable((byte)100), new ShortWritable((short)551), new LongWritable(900L), new HiveDecimalWritable(HiveDecimal.create("983723.005")));
+    db.addRow(new DoubleWritable(500), new IntWritable(22345),  new DoubleWritable(-23.000), new FloatWritable(-3f),
+        new ByteWritable((byte)100), new ShortWritable((short)2321), new LongWritable(9200L), new HiveDecimalWritable(HiveDecimal.create("-932032.7")));
+    return db.createRows();
+  }
+
+  @Override
+  public List<ExprNodeDesc> getExpressionList() throws UDFArgumentException {
+    List<ExprNodeDesc> exprs = new ArrayList<ExprNodeDesc>(cols.length);
+    for (int i = 0; i < cols.length; i++) {
+      exprs.add(OperatorTestUtils.getStringColumn(cols[i]));
+    }
+
+    ExprNodeDesc[] scales = { new ExprNodeConstantDesc(TypeInfoFactory.intTypeInfo, -2),
+        new ExprNodeConstantDesc(TypeInfoFactory.byteTypeInfo, (byte)0),
+        new ExprNodeConstantDesc(TypeInfoFactory.shortTypeInfo, (short)3),
+        new ExprNodeConstantDesc(TypeInfoFactory.intTypeInfo, 0),
+        new ExprNodeConstantDesc(TypeInfoFactory.longTypeInfo, -2L),
+        new ExprNodeConstantDesc(TypeInfoFactory.intTypeInfo, 0),
+        new ExprNodeConstantDesc(TypeInfoFactory.intTypeInfo, -2),
+        new ExprNodeConstantDesc(TypeInfoFactory.intTypeInfo, 3) };
+
+    List<ExprNodeDesc> earr = new ArrayList<ExprNodeDesc>();
+    for (int j = 0; j < cols.length; j++) {
+      ExprNodeDesc r = TypeCheckProcFactory.DefaultExprProcessor.getFuncExprNodeDesc("round", exprs.get(j), scales[j]);
+      earr.add(r);
+    }
+
+    return earr;
+  }
+
+  @Test
+  public void testDecimalRoundingMetaData() throws UDFArgumentException {
+    GenericUDFRound udf = new GenericUDFRound();
+    ObjectInspector[] inputOIs = {
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(TypeInfoFactory.getDecimalTypeInfo(7, 3)),
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.intTypeInfo, new IntWritable(2))
+    };
+    PrimitiveObjectInspector outputOI = (PrimitiveObjectInspector) udf.initialize(inputOIs);
+    DecimalTypeInfo outputTypeInfo = (DecimalTypeInfo)outputOI.getTypeInfo();
+    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(7, 2), outputTypeInfo);
+  }
+
+  @Test
+  public void testDecimalRoundingMetaData1() throws UDFArgumentException {
+    GenericUDFRound udf = new GenericUDFRound();
+    ObjectInspector[] inputOIs = {
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(TypeInfoFactory.getDecimalTypeInfo(7, 3)),
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.intTypeInfo, new IntWritable(-2))
+    };
+    PrimitiveObjectInspector outputOI = (PrimitiveObjectInspector) udf.initialize(inputOIs);
+    DecimalTypeInfo outputTypeInfo = (DecimalTypeInfo)outputOI.getTypeInfo();
+    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(5, 0), outputTypeInfo);
+  }
+
+  @Test
+  public void testDecimalRoundingMetaData2() throws UDFArgumentException {
+    GenericUDFRound udf = new GenericUDFRound();
+    ObjectInspector[] inputOIs = {
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(TypeInfoFactory.getDecimalTypeInfo(7, 3)),
+        PrimitiveObjectInspectorFactory.getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.intTypeInfo, new IntWritable(5))
+    };
+    PrimitiveObjectInspector outputOI = (PrimitiveObjectInspector) udf.initialize(inputOIs);
+    DecimalTypeInfo outputTypeInfo = (DecimalTypeInfo)outputOI.getTypeInfo();
+    Assert.assertEquals(TypeInfoFactory.getDecimalTypeInfo(9, 5), outputTypeInfo);
+  }
+
+}

Modified: hive/trunk/ql/src/test/queries/clientpositive/udf_round.q
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/queries/clientpositive/udf_round.q?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/test/queries/clientpositive/udf_round.q (original)
+++ hive/trunk/ql/src/test/queries/clientpositive/udf_round.q Mon Nov  4 21:32:20 2013
@@ -42,5 +42,5 @@ SELECT
   round(3.141592653589793, 15), round(3.141592653589793, 16)
 FROM src tablesample (1 rows);
 
-SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9)
+SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9), round(1809242.3151111344BD, 9), round(-1809242.3151111344BD, 9)
 FROM src tablesample (1 rows);

Modified: hive/trunk/ql/src/test/results/clientpositive/decimal_udf.q.out
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/clientpositive/decimal_udf.q.out?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/test/results/clientpositive/decimal_udf.q.out (original)
+++ hive/trunk/ql/src/test/results/clientpositive/decimal_udf.q.out Mon Nov  4 21:32:20 2013
@@ -1742,7 +1742,7 @@ STAGE PLANS:
           Select Operator
             expressions:
                   expr: round(key, 2)
-                  type: decimal(65,30)
+                  type: decimal(38,2)
             outputColumnNames: _col0
             ListSink
 

Modified: hive/trunk/ql/src/test/results/clientpositive/udf_round.q.out
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/clientpositive/udf_round.q.out?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/test/results/clientpositive/udf_round.q.out (original)
+++ hive/trunk/ql/src/test/results/clientpositive/udf_round.q.out Mon Nov  4 21:32:20 2013
@@ -40,7 +40,7 @@ FROM src tablesample (1 rows)
 POSTHOOK: type: QUERY
 POSTHOOK: Input: default@src
 #### A masked pattern was here ####
-55555	55555.0	55555.0	55555.0	55555.0	55560.0	55600.0	56000.0	60000.0	100000.0	0.0	0.0	0.0
+55555	55555	55555	55555	55555	55560	55600	56000	60000	100000	0	0	0
 PREHOOK: query: SELECT
   round(125.315), round(125.315, 0),
   round(125.315, 1), round(125.315, 2), round(125.315, 3), round(125.315, 4),
@@ -109,14 +109,14 @@ POSTHOOK: type: QUERY
 POSTHOOK: Input: default@src
 #### A masked pattern was here ####
 0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	3.0	3.1	3.14	3.142	3.1416	3.14159	3.141593	3.1415927	3.14159265	3.141592654	3.1415926536	3.14159265359	3.14159265359	3.1415926535898	3.1415926535898	3.14159265358979	3.141592653589793	3.141592653589793
-PREHOOK: query: SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9)
+PREHOOK: query: SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9), round(1809242.3151111344BD, 9), round(-1809242.3151111344BD, 9)
 FROM src tablesample (1 rows)
 PREHOOK: type: QUERY
 PREHOOK: Input: default@src
 #### A masked pattern was here ####
-POSTHOOK: query: SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9)
+POSTHOOK: query: SELECT round(1809242.3151111344, 9), round(-1809242.3151111344, 9), round(1809242.3151111344BD, 9), round(-1809242.3151111344BD, 9)
 FROM src tablesample (1 rows)
 POSTHOOK: type: QUERY
 POSTHOOK: Input: default@src
 #### A masked pattern was here ####
-1809242.315111134	-1809242.315111134
+1809242.315111134	-1809242.315111134	1809242.315111134	-1809242.315111134

Modified: hive/trunk/ql/src/test/results/compiler/plan/udf4.q.xml
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/compiler/plan/udf4.q.xml?rev=1538778&r1=1538777&r2=1538778&view=diff
==============================================================================
--- hive/trunk/ql/src/test/results/compiler/plan/udf4.q.xml (original)
+++ hive/trunk/ql/src/test/results/compiler/plan/udf4.q.xml Mon Nov  4 21:32:20 2013
@@ -835,14 +835,7 @@
                  </object> 
                 </void> 
                 <void property="genericUDF"> 
-                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge"> 
-                  <void property="udfClassName"> 
-                   <string>org.apache.hadoop.hive.ql.udf.UDFRound</string> 
-                  </void> 
-                  <void property="udfName"> 
-                   <string>round</string> 
-                  </void> 
-                 </object> 
+                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFRound"/> 
                 </void> 
                 <void property="typeInfo"> 
                  <object idref="PrimitiveTypeInfo0"/> 
@@ -867,14 +860,7 @@
                  </object> 
                 </void> 
                 <void property="genericUDF"> 
-                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge"> 
-                  <void property="udfClassName"> 
-                   <string>org.apache.hadoop.hive.ql.udf.UDFRound</string> 
-                  </void> 
-                  <void property="udfName"> 
-                   <string>round</string> 
-                  </void> 
-                 </object> 
+                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFRound"/> 
                 </void> 
                 <void property="typeInfo"> 
                  <object idref="PrimitiveTypeInfo0"/> 
@@ -1243,14 +1229,7 @@
                  </object> 
                 </void> 
                 <void property="genericUDF"> 
-                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge"> 
-                  <void property="udfClassName"> 
-                   <string>org.apache.hadoop.hive.ql.udf.UDFRound</string> 
-                  </void> 
-                  <void property="udfName"> 
-                   <string>round</string> 
-                  </void> 
-                 </object> 
+                 <object class="org.apache.hadoop.hive.ql.udf.generic.GenericUDFRound"/> 
                 </void> 
                 <void property="typeInfo"> 
                  <object idref="PrimitiveTypeInfo0"/>