Repository: incubator-impala
Updated Branches:
  refs/heads/master 870839dc1 -> 4e7172f6f


IMPALA-2459: Implement next_day date/time UDF

Returns the date of the weekday that follows a particular date.
The weekday argument is a string literal indicating the day of the week.
Also this argument is case-insensitive. Available values are:
"Sunday"/"SUN", "Monday"/"MON", "Tuesday"/"TUE",
"Wednesday"/"WED", "Thursday"/"THU", "Friday"/"FRI", "Saturday"/"SAT".
For example, the first Saturday after Wednesday, 25 December 2013
is on 28 December 2013.
select next_day('2013-12-25','Saturday') returns '2013-12-28 00:00:00'
select next_day(to_timestamp('08-1987-21', 'MM-yyyy-dd'), 'FRIDAY')
returns '1987-08-28 00:00:00'

Change-Id: I2721d236c096639a9e7d2df8a45ca888c6b3e83e
Reviewed-on: http://gerrit.cloudera.org:8080/1943
Reviewed-by: Lars Volker <[email protected]>
Tested-by: Lars Volker <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/4e7172f6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/4e7172f6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/4e7172f6

Branch: refs/heads/master
Commit: 4e7172f6f5bf8a836fbb0c495ce8bdefecc2d6e5
Parents: 870839d
Author: Hayabusa-intel <[email protected]>
Authored: Fri May 27 09:05:29 2016 -0400
Committer: Tim Armstrong <[email protected]>
Committed: Thu Jun 9 04:30:48 2016 -0700

----------------------------------------------------------------------
 be/src/exprs/expr-test.cc                    | 79 +++++++++++++++++++++++
 be/src/exprs/timestamp-functions-ir.cc       | 32 +++++++++
 be/src/exprs/timestamp-functions.h           | 11 ++++
 common/function-registry/impala_functions.py |  1 +
 4 files changed, 123 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/4e7172f6/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index 3c316e1..4147093 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -267,6 +267,80 @@ class ExprTest : public testing::Test {
     return results;
   }
 
+  void TestNextDayFunction(){
+    // Sequential test cases
+    TestTimestampValue("next_day('2016-05-01','Sunday')",
+      TimestampValue("2016-05-08 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Monday')",
+      TimestampValue("2016-05-02 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Tuesday')",
+      TimestampValue("2016-05-03 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Wednesday')",
+      TimestampValue("2016-05-04 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Thursday')",
+      TimestampValue("2016-05-05 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Friday')",
+      TimestampValue("2016-05-06 00:00:00", 19));
+    TestTimestampValue("next_day('2016-05-01','Saturday')",
+      TimestampValue("2016-05-07 00:00:00", 19));
+
+    // Random test cases
+    TestTimestampValue("next_day('1910-01-18','SunDay')",
+      TimestampValue("1910-01-23 00:00:00", 19));
+    TestTimestampValue("next_day('1916-06-05', 'SUN')",
+      TimestampValue("1916-06-11 00:00:00", 19));
+    TestTimestampValue("next_day('1932-11-08','monday')",
+      TimestampValue("1932-11-14 00:00:00", 19));
+    TestTimestampValue("next_day('1933-09-11','Mon')",
+      TimestampValue("1933-09-18 00:00:00", 19));
+    TestTimestampValue("next_day('1934-03-21','TUeSday')",
+      TimestampValue("1934-03-27 00:00:00", 19));
+    TestTimestampValue("next_day('1954-02-25','tuE')",
+      TimestampValue("1954-03-02 00:00:00", 19));
+    TestTimestampValue("next_day('1965-04-18','WeDneSdaY')",
+      TimestampValue("1965-04-21 00:00:00", 19));
+    TestTimestampValue("next_day('1966-08-29','wed')",
+      TimestampValue("1966-08-31 00:00:00", 19));
+    TestTimestampValue("next_day('1968-07-23','tHurSday')",
+      TimestampValue("1968-07-25 00:00:00", 19));
+    TestTimestampValue("next_day('1969-05-28','thu')",
+      TimestampValue("1969-05-29 00:00:00", 19));
+    TestTimestampValue("next_day('1989-10-12','fRIDay')",
+      TimestampValue("1989-10-13 00:00:00", 19));
+    TestTimestampValue("next_day('1973-10-02','frI')",
+      TimestampValue("1973-10-05 00:00:00", 19));
+    TestTimestampValue("next_day('2000-02-29','saTUrDaY')",
+      TimestampValue("2000-03-04 00:00:00", 19));
+    TestTimestampValue("next_day('2013-04-12','sat')",
+      TimestampValue("2013-04-13 00:00:00", 19));
+    TestTimestampValue("next_day('2013-12-25','Saturday')",
+      TimestampValue("2013-12-28 00:00:00", 19));
+
+    // Explicit timestamp conversion tests
+    TestTimestampValue("next_day(to_timestamp('12-27-2008', 'MM-dd-yyyy'), 
'moN')",
+      TimestampValue("2008-12-29 00:00:00", 19));
+    TestTimestampValue("next_day(to_timestamp('2007-20-10 11:22', 'yyyy-dd-MM 
HH:mm'),\
+      'TUeSdaY')", TimestampValue("2007-10-23 11:22:00", 19));
+    TestTimestampValue("next_day(to_timestamp('18-11-2070 09:12', 'dd-MM-yyyy 
HH:mm'),\
+      'WeDneSdaY')", TimestampValue("2070-11-19 09:12:00", 19));
+    TestTimestampValue("next_day(to_timestamp('12-1900-05', 'dd-yyyy-MM'), 
'tHurSday')",
+      TimestampValue("1900-05-17 00:00:00", 19));
+    TestTimestampValue("next_day(to_timestamp('08-1987-21', 'MM-yyyy-dd'), 
'FRIDAY')",
+      TimestampValue("1987-08-28 00:00:00", 19));
+    TestTimestampValue("next_day(to_timestamp('02-04-2001', 'dd-MM-yyyy'), 
'SAT')",
+      TimestampValue("2001-04-07 00:00:00", 19));
+    TestTimestampValue("next_day(to_timestamp('1970-01-31 00:00:00',\
+      'yyyy-MM-dd HH:mm:ss'), 'SunDay')", TimestampValue("1970-02-01 
00:00:00", 19));
+
+    // Invalid input: unacceptable date parameter
+    TestIsNull("next_day('12202010','Saturday')", TYPE_TIMESTAMP);
+    TestIsNull("next_day('2011 02 11','thu')", TYPE_TIMESTAMP);
+    TestIsNull("next_day('09-19-2012xyz','monDay')", TYPE_TIMESTAMP);
+    TestIsNull("next_day('000000000000000','wed')", TYPE_TIMESTAMP);
+    TestIsNull("next_day('hell world!','fRiDaY')", TYPE_TIMESTAMP);
+    TestIsNull("next_day('t1c7t0c9','sunDAY')", TYPE_TIMESTAMP);
+  }
+
 // This macro adds a scoped trace to provide the line number of the caller 
upon failure.
 #define EXPECT_BETWEEN(start, value, end) { \
     SCOPED_TRACE(""); \
@@ -4346,8 +4420,13 @@ TEST_F(ExprTest, TimestampFunctions) {
   TestIsNull("unix_timestamp('12/2/2015', 'MM/dd/yyyy')", TYPE_BIGINT);
   TestValue("unix_timestamp('12/31/2015', 'MM/d/yyyy')", TYPE_BIGINT, 
1451520000);
   TestValue("unix_timestamp('12/31/2015', 'MM/dd/yyyy')", TYPE_BIGINT, 
1451520000);
+
+  // next_day udf test for IMPALA-2459
+  TestNextDayFunction();
 }
 
+
+
 TEST_F(ExprTest, ConditionalFunctions) {
   // If first param evaluates to true, should return second parameter,
   // false or NULL should return the third.

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/4e7172f6/be/src/exprs/timestamp-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/timestamp-functions-ir.cc 
b/be/src/exprs/timestamp-functions-ir.cc
index 08992d9..05bc6ee 100644
--- a/be/src/exprs/timestamp-functions-ir.cc
+++ b/be/src/exprs/timestamp-functions-ir.cc
@@ -573,6 +573,38 @@ DoubleVal 
TimestampFunctions::MonthsBetween(FunctionContext* context,
   return DoubleVal(months_between);
 }
 
+TimestampVal TimestampFunctions::NextDay(FunctionContext* context,
+    const TimestampVal& date, const StringVal& weekday) {
+  string weekday_str = string(reinterpret_cast<const char*>(weekday.ptr), 
weekday.len);
+  transform(weekday_str.begin(), weekday_str.end(), weekday_str.begin(), 
tolower);
+  int day_idx = 0;
+  if (weekday_str == "sunday" || weekday_str == "sun") {
+    day_idx = 1;
+  } else if (weekday_str == "monday" || weekday_str == "mon") {
+    day_idx = 2;
+  } else if (weekday_str == "tuesday" || weekday_str == "tue") {
+    day_idx = 3;
+  } else if (weekday_str == "wednesday" || weekday_str == "wed") {
+    day_idx = 4;
+  } else if (weekday_str == "thursday" || weekday_str == "thu") {
+    day_idx = 5;
+  } else if (weekday_str == "friday" || weekday_str == "fri") {
+    day_idx = 6;
+  } else if (weekday_str == "saturday" || weekday_str == "sat") {
+    day_idx = 7;
+  }
+  DCHECK_GE(day_idx, 1);
+  DCHECK_LE(day_idx, 7);
+
+  int delta_days = day_idx - DayOfWeek(context, date).val;
+  delta_days = delta_days <= 0 ? delta_days + 7 : delta_days;
+  DCHECK_GE(delta_days, 1);
+  DCHECK_LE(delta_days, 7);
+
+  IntVal delta(delta_days);
+  return AddSub<true, IntVal, Days, false>(context, date, delta);
+}
+
 IntVal TimestampFunctions::IntMonthsBetween(FunctionContext* context,
     const TimestampVal& ts1, const TimestampVal& ts2) {
   if (ts1.is_null || ts2.is_null) return IntVal::null();

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/4e7172f6/be/src/exprs/timestamp-functions.h
----------------------------------------------------------------------
diff --git a/be/src/exprs/timestamp-functions.h 
b/be/src/exprs/timestamp-functions.h
index 23c0d10..6738bd0 100644
--- a/be/src/exprs/timestamp-functions.h
+++ b/be/src/exprs/timestamp-functions.h
@@ -141,6 +141,17 @@ class TimestampFunctions {
   static DoubleVal MonthsBetween(FunctionContext* context,
       const TimestampVal& ts_val1, const TimestampVal& ts_val2);
 
+  /// Return the date of the weekday that follows a particular date.
+  /// The 'weekday' argument is a string literal indicating the day of the 
week.
+  /// Also this argument is case-insensitive. Available values are:
+  /// "Sunday"/"SUN", "Monday"/"MON", "Tuesday"/"TUE",
+  /// "Wednesday"/"WED", "Thursday"/"THU", "Friday"/"FRI", "Saturday"/"SAT".
+  /// For example, the first Saturday after Wednesday, 25 December 2013
+  /// is on 28 December 2013.
+  /// select next_day('2013-12-25','Saturday') returns '2013-12-28'
+  static TimestampVal NextDay(FunctionContext* context, const TimestampVal& 
date,
+      const StringVal& weekday);
+
   /// Add/sub functions on the timestamp. This handles three forms of 
adding/subtracting
   /// intervals to/from timestamps:
   ///   1) ADD/SUB_<INTERVAL>(<TIMESTAMP>, <NUMBER>),

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/4e7172f6/common/function-registry/impala_functions.py
----------------------------------------------------------------------
diff --git a/common/function-registry/impala_functions.py 
b/common/function-registry/impala_functions.py
index 879ff8a..86a60e0 100644
--- a/common/function-registry/impala_functions.py
+++ b/common/function-registry/impala_functions.py
@@ -106,6 +106,7 @@ visible_functions = [
     
'_ZN6impala11UdfBuiltins9VectorGetEPN10impala_udf15FunctionContextERKNS1_9BigIntValERKNS1_9StringValE'],
 
   # Timestamp functions
+  [['next_day'], 'TIMESTAMP', ['TIMESTAMP', 'STRING'], 
'_ZN6impala18TimestampFunctions7NextDayEPN10impala_udf15FunctionContextERKNS1_12TimestampValERKNS1_9StringValE'],
   [['unix_timestamp'], 'BIGINT', ['STRING'], 
'_ZN6impala18TimestampFunctions14UnixFromStringEPN10impala_udf15FunctionContextERKNS1_9StringValE'],
   [['year'], 'INT', ['TIMESTAMP'], 
'_ZN6impala18TimestampFunctions4YearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
   [['month'], 'INT', ['TIMESTAMP'], 
'_ZN6impala18TimestampFunctions5MonthEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],

Reply via email to