Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id EFD0D200CA8 for ; Thu, 15 Jun 2017 22:38:46 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id ED3E4160BED; Thu, 15 Jun 2017 20:38:46 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 196FE160BC9 for ; Thu, 15 Jun 2017 22:38:45 +0200 (CEST) Received: (qmail 81318 invoked by uid 500); 15 Jun 2017 20:38:45 -0000 Mailing-List: contact commits-help@impala.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@impala.incubator.apache.org Delivered-To: mailing list commits@impala.incubator.apache.org Received: (qmail 81309 invoked by uid 99); 15 Jun 2017 20:38:45 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Jun 2017 20:38:45 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id CD8B3C663C for ; Thu, 15 Jun 2017 20:38:44 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -4.231 X-Spam-Level: X-Spam-Status: No, score=-4.231 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id PdZ3y93GRrq8 for ; Thu, 15 Jun 2017 20:38:43 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id A4B765F36F for ; Thu, 15 Jun 2017 20:38:42 +0000 (UTC) Received: (qmail 81294 invoked by uid 99); 15 Jun 2017 20:38:41 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Jun 2017 20:38:41 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 096EBE04B1; Thu, 15 Jun 2017 20:38:41 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: tarmstrong@apache.org To: commits@impala.incubator.apache.org Date: Thu, 15 Jun 2017 20:38:42 -0000 Message-Id: <4752f13e0e93457d862c0263575e8a2b@git.apache.org> In-Reply-To: <8a07d13b079f4a7d9010023d042f16ce@git.apache.org> References: <8a07d13b079f4a7d9010023d042f16ce@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/3] incubator-impala git commit: IMPALA-5316: Adds last_day() function archived-at: Thu, 15 Jun 2017 20:38:47 -0000 IMPALA-5316: Adds last_day() function This change adds last_day() function. The function takes exactly one TIMESTAMP argument and returns a TIMESTAMP that is the last date of the input date's calendar month. The function will return NULL when: 1) The input argument cannot be implicitly casted to a TIMESTAMP. 2) The TIMESTAMP argument is missing a date component. 3) The TIMESTAMP argument is outside of the supported range: between 1400-01-31 00:00:00 and 9999-12-31 23:59:59 Change-Id: I429c8734bddca3c37a2eedc211a16a4ffcb04370 Reviewed-on: http://gerrit.cloudera.org:8080/6991 Reviewed-by: Matthew Jacobs Tested-by: Impala Public Jenkins Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/d5b6cb90 Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/d5b6cb90 Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/d5b6cb90 Branch: refs/heads/master Commit: d5b6cb903de24c95de9000c473a6ddfca8516412 Parents: df2b5a9 Author: Vincent Tran Authored: Thu May 25 08:02:00 2017 -0400 Committer: Impala Public Jenkins Committed: Thu Jun 15 04:51:49 2017 +0000 ---------------------------------------------------------------------- be/src/exprs/expr-test.cc | 53 +++++++++++++++++++++++ be/src/exprs/timestamp-functions-ir.cc | 12 +++++ be/src/exprs/timestamp-functions.h | 9 ++++ common/function-registry/impala_functions.py | 1 + 4 files changed, 75 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/d5b6cb90/be/src/exprs/expr-test.cc ---------------------------------------------------------------------- diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc index dcbdeef..2aa4537 100644 --- a/be/src/exprs/expr-test.cc +++ b/be/src/exprs/expr-test.cc @@ -276,6 +276,59 @@ class ExprTest : public testing::Test { return results; } + void TestLastDayFunction() { + // Test common months (with and without time component). + TestTimestampValue("last_day('2003-01-02 04:24:04.1579')", + TimestampValue::Parse("2003-01-31 00:00:00", 19)); + TestTimestampValue("last_day('2003-02-02')", + TimestampValue::Parse("2003-02-28 00:00:00")); + TestTimestampValue("last_day('2003-03-02 03:21:12.0058')", + TimestampValue::Parse("2003-03-31 00:00:00")); + TestTimestampValue("last_day('2003-04-02')", + TimestampValue::Parse("2003-04-30 00:00:00")); + TestTimestampValue("last_day('2003-05-02')", + TimestampValue::Parse("2003-05-31 00:00:00")); + TestTimestampValue("last_day('2003-06-02')", + TimestampValue::Parse("2003-06-30 00:00:00")); + TestTimestampValue("last_day('2003-07-02 00:01:01.125')", + TimestampValue::Parse("2003-07-31 00:00:00")); + TestTimestampValue("last_day('2003-08-02')", + TimestampValue::Parse("2003-08-31 00:00:00")); + TestTimestampValue("last_day('2003-09-02')", + TimestampValue::Parse("2003-09-30 00:00:00")); + TestTimestampValue("last_day('2003-10-02')", + TimestampValue::Parse("2003-10-31 00:00:00")); + TestTimestampValue("last_day('2003-11-02 12:30:16')", + TimestampValue::Parse("2003-11-30 00:00:00")); + TestTimestampValue("last_day('2003-12-02')", + TimestampValue::Parse("2003-12-31 00:00:00")); + + // Test leap years and special cases. + TestTimestampValue("last_day('2004-02-13')", + TimestampValue::Parse("2004-02-29 00:00:00")); + TestTimestampValue("last_day('2008-02-13')", + TimestampValue::Parse("2008-02-29 00:00:00")); + TestTimestampValue("last_day('2000-02-13')", + TimestampValue::Parse("2000-02-29 00:00:00")); + TestTimestampValue("last_day('1900-02-13')", + TimestampValue::Parse("1900-02-28 00:00:00")); + TestTimestampValue("last_day('2100-02-13')", + TimestampValue::Parse("2100-02-28 00:00:00")); + + // Test corner cases. + TestTimestampValue("last_day('1400-01-01 00:00:00')", + TimestampValue::Parse("1400-01-31 00:00:00")); + TestTimestampValue("last_day('9999-12-31 23:59:59')", + TimestampValue::Parse("9999-12-31 00:00:00")); + + // Test invalid input. + TestIsNull("last_day('12202010')", TYPE_TIMESTAMP); + TestIsNull("last_day('')", TYPE_TIMESTAMP); + TestIsNull("last_day(NULL)", TYPE_TIMESTAMP); + TestIsNull("last_day('02-13-2014')", TYPE_TIMESTAMP); + TestIsNull("last_day('00:00:00')", TYPE_TIMESTAMP); + } + void TestNextDayFunction() { // Sequential test cases TestTimestampValue("next_day('2016-05-01','Sunday')", http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/d5b6cb90/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 b1aae03..6a25ced 100644 --- a/be/src/exprs/timestamp-functions-ir.cc +++ b/be/src/exprs/timestamp-functions-ir.cc @@ -38,6 +38,7 @@ using boost::gregorian::max_date_time; using boost::gregorian::min_date_time; using boost::posix_time::not_a_date_time; using boost::posix_time::ptime; +using boost::posix_time::time_duration; using namespace impala_udf; using namespace strings; @@ -564,6 +565,17 @@ TimestampVal TimestampFunctions::NextDay(FunctionContext* context, return AddSub(context, date, delta); } +TimestampVal TimestampFunctions::LastDay(FunctionContext* context, + const TimestampVal& ts) { + if (ts.is_null) return TimestampVal::null(); + const TimestampValue& timestamp = TimestampValue::FromTimestampVal(ts); + if (!timestamp.HasDate()) return TimestampVal::null(); + TimestampValue tsv(timestamp.date().end_of_month(), time_duration(0,0,0,0)); + TimestampVal rt_date; + tsv.ToTimestampVal(&rt_date); + return rt_date; +} + 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/d5b6cb90/be/src/exprs/timestamp-functions.h ---------------------------------------------------------------------- diff --git a/be/src/exprs/timestamp-functions.h b/be/src/exprs/timestamp-functions.h index 3c48567..b02e7bd 100644 --- a/be/src/exprs/timestamp-functions.h +++ b/be/src/exprs/timestamp-functions.h @@ -199,6 +199,15 @@ class TimestampFunctions { static TimestampVal AddSub(FunctionContext* context, const TimestampVal& timestamp, const AnyIntVal& num_interval_units); + /// Return the last date in the month of a specified input date. + /// The TIMESTAMP argument requires a date component, + /// it may or may not have a time component. + /// The function will return a NULL TimestampVal when: + /// 1) The TIMESTAMP argument is missing a date component. + /// 2) The TIMESTAMP argument is outside of the supported range: + /// between 1400-01-31 00:00:00 and 9999-12-31 23:59:59 + static TimestampVal LastDay(FunctionContext* context, const TimestampVal& ts); + /// Helper function to check date/time format strings. /// TODO: eventually return format converted from Java to Boost. static StringValue* CheckFormat(StringValue* format); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/d5b6cb90/common/function-registry/impala_functions.py ---------------------------------------------------------------------- diff --git a/common/function-registry/impala_functions.py b/common/function-registry/impala_functions.py index 8f8f07e..b80261c 100644 --- a/common/function-registry/impala_functions.py +++ b/common/function-registry/impala_functions.py @@ -110,6 +110,7 @@ visible_functions = [ # Timestamp functions [['next_day'], 'TIMESTAMP', ['TIMESTAMP', 'STRING'], '_ZN6impala18TimestampFunctions7NextDayEPN10impala_udf15FunctionContextERKNS1_12TimestampValERKNS1_9StringValE'], + [['last_day'], 'TIMESTAMP', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions7LastDayEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'], [['unix_timestamp'], 'BIGINT', ['STRING'], '_ZN6impala18TimestampFunctions14UnixFromStringEPN10impala_udf15FunctionContextERKNS1_9StringValE'], [['year'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions4YearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'], [['month'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions5MonthEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],