You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by jd...@apache.org on 2015/01/19 20:43:40 UTC
svn commit: r1653090 - in /hive/trunk/ql/src:
java/org/apache/hadoop/hive/ql/exec/
java/org/apache/hadoop/hive/ql/udf/generic/
test/org/apache/hadoop/hive/ql/udf/generic/ test/queries/clientpositive/
test/results/beelinepositive/ test/results/clientpos...
Author: jdere
Date: Mon Jan 19 19:43:40 2015
New Revision: 1653090
URL: http://svn.apache.org/r1653090
Log:
HIVE-9357: Create ADD_MONTHS UDF (Alexander Pivovarov via Jason Dere)
Added:
hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFAddMonths.java
hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFAddMonths.java
hive/trunk/ql/src/test/queries/clientpositive/udf_add_months.q
hive/trunk/ql/src/test/results/beelinepositive/udf_add_months.q.out
hive/trunk/ql/src/test/results/clientpositive/udf_add_months.q.out
Modified:
hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
hive/trunk/ql/src/test/results/clientpositive/show_functions.q.out
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=1653090&r1=1653089&r2=1653090&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 Jan 19 19:43:40 2015
@@ -278,6 +278,7 @@ public final class FunctionRegistry {
registerGenericUDF("date_add", GenericUDFDateAdd.class);
registerGenericUDF("date_sub", GenericUDFDateSub.class);
registerGenericUDF("datediff", GenericUDFDateDiff.class);
+ registerGenericUDF("add_months", GenericUDFAddMonths.class);
registerUDF("get_json_object", UDFJson.class, false);
Added: hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFAddMonths.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFAddMonths.java?rev=1653090&view=auto
==============================================================================
--- hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFAddMonths.java (added)
+++ hive/trunk/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFAddMonths.java Mon Jan 19 19:43:40 2015
@@ -0,0 +1,191 @@
+/**
+ * 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.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+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.UDFArgumentTypeException;
+import org.apache.hadoop.hive.ql.metadata.HiveException;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
+import org.apache.hadoop.hive.serde2.io.DateWritable;
+import org.apache.hadoop.hive.serde2.io.TimestampWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+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.PrimitiveObjectInspectorConverter.TimestampConverter;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
+import org.apache.hadoop.io.IntWritable;
+import org.apache.hadoop.io.Text;
+
+/**
+ * GenericUDFAddMonths.
+ *
+ * Add a number of months to the date. The time part of the string will be
+ * ignored.
+ *
+ */
+@Description(name = "add_months",
+ value = "_FUNC_(start_date, num_months) - Returns the date that is num_months after start_date.",
+ extended = "start_date is a string in the format 'yyyy-MM-dd HH:mm:ss' or"
+ + " 'yyyy-MM-dd'. num_months is a number. The time part of start_date is "
+ + "ignored.\n"
+ + "Example:\n " + " > SELECT _FUNC_('2009-08-31', 1) FROM src LIMIT 1;\n" + " '2009-09-30'")
+public class GenericUDFAddMonths extends GenericUDF {
+ private transient SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ private transient TimestampConverter timestampConverter;
+ private transient Converter textConverter;
+ private transient Converter dateWritableConverter;
+ private transient Converter intWritableConverter;
+ private transient PrimitiveCategory inputType1;
+ private transient PrimitiveCategory inputType2;
+ private final Calendar calendar = Calendar.getInstance();
+ private final Text output = new Text();
+
+ @Override
+ public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
+ if (arguments.length != 2) {
+ throw new UDFArgumentLengthException("add_months() requires 2 argument, got "
+ + arguments.length);
+ }
+ if (arguments[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
+ throw new UDFArgumentTypeException(0, "Only primitive type arguments are accepted but "
+ + arguments[0].getTypeName() + " is passed. as first arguments");
+ }
+ if (arguments[1].getCategory() != ObjectInspector.Category.PRIMITIVE) {
+ throw new UDFArgumentTypeException(1, "Only primitive type arguments are accepted but "
+ + arguments[2].getTypeName() + " is passed. as second arguments");
+ }
+ inputType1 = ((PrimitiveObjectInspector) arguments[0]).getPrimitiveCategory();
+ ObjectInspector outputOI = PrimitiveObjectInspectorFactory.writableStringObjectInspector;
+ switch (inputType1) {
+ case STRING:
+ case VARCHAR:
+ case CHAR:
+ inputType1 = PrimitiveCategory.STRING;
+ textConverter = ObjectInspectorConverters.getConverter(
+ (PrimitiveObjectInspector) arguments[0],
+ PrimitiveObjectInspectorFactory.writableStringObjectInspector);
+ break;
+ case TIMESTAMP:
+ timestampConverter = new TimestampConverter((PrimitiveObjectInspector) arguments[0],
+ PrimitiveObjectInspectorFactory.writableTimestampObjectInspector);
+ break;
+ case DATE:
+ dateWritableConverter = ObjectInspectorConverters.getConverter(
+ (PrimitiveObjectInspector) arguments[0],
+ PrimitiveObjectInspectorFactory.writableDateObjectInspector);
+ break;
+ default:
+ throw new UDFArgumentException(
+ " ADD_MONTHS() only takes STRING/TIMESTAMP/DATEWRITABLE types as first argument, got "
+ + inputType1);
+ }
+ inputType2 = ((PrimitiveObjectInspector) arguments[1]).getPrimitiveCategory();
+ if (inputType2 != PrimitiveCategory.INT) {
+ throw new UDFArgumentException(" ADD_MONTHS() only takes INT types as second argument, got "
+ + inputType2);
+ }
+ intWritableConverter = ObjectInspectorConverters.getConverter(
+ (PrimitiveObjectInspector) arguments[1],
+ PrimitiveObjectInspectorFactory.writableIntObjectInspector);
+ return outputOI;
+ }
+
+ @Override
+ public Object evaluate(DeferredObject[] arguments) throws HiveException {
+ if (arguments[0].get() == null) {
+ return null;
+ }
+ IntWritable toBeAdded = (IntWritable) intWritableConverter.convert(arguments[1].get());
+ if (toBeAdded == null) {
+ return null;
+ }
+ Date date;
+ switch (inputType1) {
+ case STRING:
+ String dateString = textConverter.convert(arguments[0].get()).toString();
+ try {
+ date = formatter.parse(dateString.toString());
+ } catch (ParseException e) {
+ return null;
+ }
+ break;
+ case TIMESTAMP:
+ Timestamp ts = ((TimestampWritable) timestampConverter.convert(arguments[0].get()))
+ .getTimestamp();
+ date = ts;
+ break;
+ case DATE:
+ DateWritable dw = (DateWritable) dateWritableConverter.convert(arguments[0].get());
+ date = dw.get();
+ break;
+ default:
+ throw new UDFArgumentException(
+ "ADD_MONTHS() only takes STRING/TIMESTAMP/DATEWRITABLE types, got " + inputType1);
+ }
+ int numMonth = toBeAdded.get();
+ addMonth(date, numMonth);
+ Date newDate = calendar.getTime();
+ output.set(formatter.format(newDate));
+ return output;
+ }
+
+ @Override
+ public String getDisplayString(String[] children) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("add_months(");
+ 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();
+ }
+
+ protected Calendar addMonth(Date d, int numMonths) {
+ calendar.setTime(d);
+
+ boolean lastDatOfMonth = isLastDayOfMonth(calendar);
+
+ calendar.add(Calendar.MONTH, numMonths);
+
+ if (lastDatOfMonth) {
+ int maxDd = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ calendar.set(Calendar.DAY_OF_MONTH, maxDd);
+ }
+ return calendar;
+ }
+
+ protected boolean isLastDayOfMonth(Calendar cal) {
+ int maxDd = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
+ int dd = cal.get(Calendar.DAY_OF_MONTH);
+ return dd == maxDd;
+ }
+}
Added: hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFAddMonths.java
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFAddMonths.java?rev=1653090&view=auto
==============================================================================
--- hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFAddMonths.java (added)
+++ hive/trunk/ql/src/test/org/apache/hadoop/hive/ql/udf/generic/TestGenericUDFAddMonths.java Mon Jan 19 19:43:40 2015
@@ -0,0 +1,59 @@
+/**
+ * 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.ql.metadata.HiveException;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredJavaObject;
+import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredObject;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
+import org.apache.hadoop.io.IntWritable;
+import org.apache.hadoop.io.Text;
+
+import junit.framework.TestCase;
+
+public class TestGenericUDFAddMonths extends TestCase {
+
+ public void testAddMonths() throws HiveException {
+ GenericUDFAddMonths udf = new GenericUDFAddMonths();
+ ObjectInspector valueOI0 = PrimitiveObjectInspectorFactory.writableStringObjectInspector;
+ ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.writableIntObjectInspector;
+ ObjectInspector[] arguments = { valueOI0, valueOI1 };
+
+ udf.initialize(arguments);
+ runAndVerify("2014-01-14", 1, "2014-02-14", udf);
+ runAndVerify("2014-01-31", 1, "2014-02-28", udf);
+ runAndVerify("2014-02-28", -1, "2014-01-31", udf);
+ runAndVerify("2014-02-28", 2, "2014-04-30", udf);
+ runAndVerify("2014-04-30", -2, "2014-02-28", udf);
+ runAndVerify("2015-02-28", 12, "2016-02-29", udf);
+ runAndVerify("2016-02-29", -12, "2015-02-28", udf);
+ runAndVerify("2016-01-29", 1, "2016-02-29", udf);
+ runAndVerify("2016-02-29", -1, "2016-01-31", udf);
+ }
+
+ private void runAndVerify(String str, int months, String expResult, GenericUDF udf)
+ throws HiveException {
+ DeferredObject valueObj0 = new DeferredJavaObject(new Text(str));
+ DeferredObject valueObj1 = new DeferredJavaObject(new IntWritable(months));
+ DeferredObject[] args = { valueObj0, valueObj1 };
+ Text output = (Text) udf.evaluate(args);
+ assertEquals("add_months() test ", expResult, output.toString());
+ }
+}
Added: hive/trunk/ql/src/test/queries/clientpositive/udf_add_months.q
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/queries/clientpositive/udf_add_months.q?rev=1653090&view=auto
==============================================================================
--- hive/trunk/ql/src/test/queries/clientpositive/udf_add_months.q (added)
+++ hive/trunk/ql/src/test/queries/clientpositive/udf_add_months.q Mon Jan 19 19:43:40 2015
@@ -0,0 +1,2 @@
+DESCRIBE FUNCTION add_months;
+DESCRIBE FUNCTION EXTENDED add_months;
Added: hive/trunk/ql/src/test/results/beelinepositive/udf_add_months.q.out
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/beelinepositive/udf_add_months.q.out?rev=1653090&view=auto
==============================================================================
--- hive/trunk/ql/src/test/results/beelinepositive/udf_add_months.q.out (added)
+++ hive/trunk/ql/src/test/results/beelinepositive/udf_add_months.q.out Mon Jan 19 19:43:40 2015
@@ -0,0 +1,15 @@
+Saving all output to "!!{outputDirectory}!!/udf_add_months.q.raw". Enter "record" with no arguments to stop it.
+>>> !run !!{qFileDirectory}!!/udf_add_months.q
+>>> DESCRIBE FUNCTION add_months;
+'tab_name'
+'date_add(start_date, num_months) - Returns the date that is num_months after start_date.'
+1 row selected
+>>> DESCRIBE FUNCTION EXTENDED add_months;
+'tab_name'
+'date_add(start_date, num_months) - Returns the date that is num_months after start_date.'
+'start_date is a string in the format 'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd'. num_months is a number. The time part of start_date is ignored.'
+'Example:'
+' > SELECT add_months('2009-08-31', 1) FROM src LIMIT 1;'
+' '2009-09-30''
+5 rows selected
+>>> !record
Modified: hive/trunk/ql/src/test/results/clientpositive/show_functions.q.out
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/clientpositive/show_functions.q.out?rev=1653090&r1=1653089&r2=1653090&view=diff
==============================================================================
--- hive/trunk/ql/src/test/results/clientpositive/show_functions.q.out (original)
+++ hive/trunk/ql/src/test/results/clientpositive/show_functions.q.out Mon Jan 19 19:43:40 2015
@@ -21,6 +21,7 @@ POSTHOOK: type: SHOWFUNCTIONS
^
abs
acos
+add_months
and
array
array_contains
Added: hive/trunk/ql/src/test/results/clientpositive/udf_add_months.q.out
URL: http://svn.apache.org/viewvc/hive/trunk/ql/src/test/results/clientpositive/udf_add_months.q.out?rev=1653090&view=auto
==============================================================================
--- hive/trunk/ql/src/test/results/clientpositive/udf_add_months.q.out (added)
+++ hive/trunk/ql/src/test/results/clientpositive/udf_add_months.q.out Mon Jan 19 19:43:40 2015
@@ -0,0 +1,14 @@
+PREHOOK: query: DESCRIBE FUNCTION add_months
+PREHOOK: type: DESCFUNCTION
+POSTHOOK: query: DESCRIBE FUNCTION add_months
+POSTHOOK: type: DESCFUNCTION
+add_months(start_date, num_months) - Returns the date that is num_months after start_date.
+PREHOOK: query: DESCRIBE FUNCTION EXTENDED add_months
+PREHOOK: type: DESCFUNCTION
+POSTHOOK: query: DESCRIBE FUNCTION EXTENDED add_months
+POSTHOOK: type: DESCFUNCTION
+add_months(start_date, num_months) - Returns the date that is num_months after start_date.
+start_date is a string in the format 'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd'. num_months is a number. The time part of start_date is ignored.
+Example:
+ > SELECT add_months('2009-08-31', 1) FROM src LIMIT 1;
+ '2009-09-30'