From db82e295a76cecdd3544db52001250f6577eec66 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 8 Sep 2020 18:29:13 -0700 Subject: [PATCH 01/42] add functions day, month, quarter, year --- .../sql/expression/DSL.java | 16 ++++ .../expression/datetime/DateTimeFunction.java | 80 ++++++++++++++++++- .../function/BuiltinFunctionName.java | 4 + .../datetime/DateTimeFunctionTest.java | 62 +++++++++++++- docs/user/dql/functions.rst | 80 +++++++++++++++++-- ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 7 files changed, 234 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index ee3b4506ba..694563d21e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -244,6 +244,22 @@ public FunctionExpression dayofmonth(Expression... expressions) { return function(BuiltinFunctionName.DAYOFMONTH, expressions); } + public FunctionExpression day(Expression... expressions) { + return function(BuiltinFunctionName.DAY, expressions); + } + + public FunctionExpression month(Expression... expressions) { + return function(BuiltinFunctionName.MONTH, expressions); + } + + public FunctionExpression quarter(Expression... expressions) { + return function(BuiltinFunctionName.QUARTER, expressions); + } + + public FunctionExpression year(Expression... expressions) { + return function(BuiltinFunctionName.YEAR, expressions); + } + public FunctionExpression date(Expression... expressions) { return function(BuiltinFunctionName.DATE, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index ea4716e9a2..76a6aa7969 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -24,7 +24,6 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; -import static com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName.DAYOFMONTH; import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionDSL.define; import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionDSL.impl; import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionDSL.nullMissingHandling; @@ -38,6 +37,7 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; +import com.sun.tools.javac.comp.Lower; import lombok.experimental.UtilityClass; /** @@ -57,6 +57,10 @@ public void register(BuiltinFunctionRepository repository) { repository.register(dayOfMonth()); repository.register(time()); repository.register(timestamp()); + repository.register(day()); + repository.register(month()); + repository.register(quarter()); + repository.register(year()); } /** @@ -76,12 +80,52 @@ private FunctionResolver date() { * DAYOFMONTH(DATE). return the day of the month (1-31). */ private FunctionResolver dayOfMonth() { - return define(DAYOFMONTH.getName(), + return define(BuiltinFunctionName.DAYOFMONTH.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE) ); } + /** + * DAY(DATE). return the day of the month (1-31). + */ + private FunctionResolver day() { + return define(BuiltinFunctionName.DAY.getName(), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), + INTEGER, DATE) + ); + } + + /** + * MONTH(DATE). return the month for date (1-12). + */ + private FunctionResolver month() { + return define(BuiltinFunctionName.MONTH.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMonth), + INTEGER, DATE) + ); + } + + /** + * QUARTER(DATE). return the month for date (1-4). + */ + private FunctionResolver quarter() { + return define(BuiltinFunctionName.QUARTER.getName(), + impl(nullMissingHandling(DateTimeFunction::exprQuarter), + INTEGER, DATE) + ); + } + + /** + * YEAR(DATE). return the year for date (1000-9999). + */ + private FunctionResolver year() { + return define(BuiltinFunctionName.YEAR.getName(), + impl(nullMissingHandling(DateTimeFunction::exprYear), + INTEGER, DATE) + ); + } + /** * Extracts the time part of a date and time value. * Also to construct a time type. The supported signatures: @@ -122,13 +166,43 @@ private ExprValue exprDate(ExprValue exprValue) { } } + /** + * Month for date implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprMonth(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getMonthValue()); + } + + /** + * Quarter for date implementation for ExprValue. + * + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprQuarter(ExprValue date) { + return new ExprIntegerValue((date.dateValue().getMonthValue() % 3) == 0 + ? (date.dateValue().getMonthValue() / 3) + : ((date.dateValue().getMonthValue() / 3) + 1)); + } + + /** + * Year for date implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprYear(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getYear()); + } + /** * Day of Month implementation for ExprValue. * @param date ExprValue of Date type. * @return ExprValue. */ private ExprValue exprDayOfMonth(ExprValue date) { - return new ExprIntegerValue(date.dateValue().getMonthValue()); + return new ExprIntegerValue(date.dateValue().getDayOfMonth()); } /** diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 2edbe11d11..d4d7336a74 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -55,6 +55,10 @@ public enum BuiltinFunctionName { DAYOFMONTH(FunctionName.of("dayofmonth")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), + DAY(FunctionName.of("day")), + MONTH(FunctionName.of("month")), + QUARTER(FunctionName.of("quarter")), + YEAR(FunctionName.of("year")), /** * Text Functions. diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 1f6e35ba16..6f9c44e69f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -66,14 +66,72 @@ public void dayOfMonth() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); - FunctionExpression expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-07-07"))); + FunctionExpression expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); - assertEquals("dayofmonth(DATE '2020-07-07')", expression.toString()); + assertEquals("dayofmonth(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(7), eval(expression)); assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); } + @Test + public void day() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.day(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("day(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(7), eval(expression)); + assertEquals(nullValue(), eval(dsl.day(nullRef))); + assertEquals(missingValue(), eval(dsl.day(missingRef))); + } + + @Test + public void month() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.month(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("month(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(8), eval(expression)); + assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); + } + + @Test + public void quarter() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.quarter(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("quarter(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(3), eval(expression)); + + expression = dsl.quarter(DSL.literal(new ExprDateValue("2020-12-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("quarter(DATE '2020-12-07')", expression.toString()); + assertEquals(integerValue(4), eval(expression)); + + assertEquals(nullValue(), eval(dsl.quarter(nullRef))); + assertEquals(missingValue(), eval(dsl.quarter(missingRef))); + } + + @Test + public void year() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.year(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("year(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(2020), eval(expression)); + assertEquals(nullValue(), eval(dsl.year(nullRef))); + assertEquals(missingValue(), eval(dsl.year(missingRef))); + } + @Test public void date() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index e7edf3e7c2..9a1604c8c6 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -323,6 +323,28 @@ Specifications: 1. DATE_FORMAT(DATE, STRING) -> STRING 2. DATE_FORMAT(DATE, STRING, STRING) -> STRING +DAY +===== + +Description +----------- + +Usage: day(date) extracts the day of the month for date, in the range 1 to 31, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero day part. + +Argument type: DATE + +Return type: INTEGER + +Example:: + + od> SELECT DAY(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------+ + | DAY(DATE('2020-08-26') | + |----------------------------| + | 26 | + +----------------------------+ + DAYOFMONTH ========== @@ -598,9 +620,21 @@ MONTH Description ----------- -Specifications: +Usage: month(date) returns the month for date, in the range 1 to 12 for January to December, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero month part. -1. MONTH(DATE) -> INTEGER +Argument type: DATE + +Return type: INTEGER + +Example:: + + od> SELECT MONTH(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------+ + | MONTH(DATE('2020-08-26') | + |----------------------------| + | 8 | + +----------------------------+ MONTHNAME @@ -703,6 +737,30 @@ Example:: +---------------+----------------+--------------------+ +QUARTER +===== + +Description +----------- + +Usage: quarter(date) returns the quarter of the year for date, in the range 1 to 4. + +Argument type: DATE + +Return type: INTEGER + +Example:: + + od> SELECT QUARTER(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------+ + | QUARTER(DATE('2020-08-26') | + |----------------------------| + | 3 | + +----------------------------+ + + + RADIANS ======= @@ -1018,13 +1076,25 @@ Specifications: YEAR -==== +===== Description ----------- -Specifications: +Usage: year(date) returns the year for date, in the range 1000 to 9999, or 0 for the “zero” date. + +Argument type: DATE -1. YEAR(DATE) -> INTEGER +Return type: INTEGER + +Example:: + + od> SELECT YEAR(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------+ + | YEAR(DATE('2020-08-26') | + |----------------------------| + | 2020 | + +----------------------------+ diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index e0ea1cb86c..749ce877eb 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DATE | TIME | TIMESTAMP + : DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index e755c05b7f..bda1ed2b61 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYOFMONTH | DATE | TIME | TIMESTAMP + : DAYOFMONTH | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From e46da70828a544163ea474b93be751ec30a3a2ed Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 09:56:06 -0700 Subject: [PATCH 02/42] fix build error --- docs/user/dql/functions.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 9a1604c8c6..cf7f241ee5 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -340,7 +340,7 @@ Example:: od> SELECT DAY(DATE('2020-08-26')) fetched rows / total rows = 1/1 +----------------------------+ - | DAY(DATE('2020-08-26') | + | DAY(DATE('2020-08-26')) | |----------------------------| | 26 | +----------------------------+ @@ -631,7 +631,7 @@ Example:: od> SELECT MONTH(DATE('2020-08-26')) fetched rows / total rows = 1/1 +----------------------------+ - | MONTH(DATE('2020-08-26') | + | MONTH(DATE('2020-08-26')) | |----------------------------| | 8 | +----------------------------+ @@ -753,11 +753,11 @@ Example:: od> SELECT QUARTER(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------+ - | QUARTER(DATE('2020-08-26') | - |----------------------------| - | 3 | - +----------------------------+ + +-----------------------------+ + | QUARTER(DATE('2020-08-26')) | + |-----------------------------| + | 3 | + +-----------------------------+ @@ -1092,7 +1092,7 @@ Example:: od> SELECT YEAR(DATE('2020-08-26')) fetched rows / total rows = 1/1 +----------------------------+ - | YEAR(DATE('2020-08-26') | + | YEAR(DATE('2020-08-26')) | |----------------------------| | 2020 | +----------------------------+ From 88a878b5cc0144bb00fcd6b98a445adf795cd5ea Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 10:18:18 -0700 Subject: [PATCH 03/42] fix doctest error --- docs/user/dql/functions.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index cf7f241ee5..fa041686c8 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -339,11 +339,11 @@ Example:: od> SELECT DAY(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------+ - | DAY(DATE('2020-08-26')) | - |----------------------------| - | 26 | - +----------------------------+ + +---------------------------+ + | DAY(DATE('2020-08-26')) | + |---------------------------| + | 26 | + +---------------------------+ DAYOFMONTH @@ -630,11 +630,11 @@ Example:: od> SELECT MONTH(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------+ - | MONTH(DATE('2020-08-26')) | - |----------------------------| - | 8 | - +----------------------------+ + +---------------------------+ + | MONTH(DATE('2020-08-26')) | + |---------------------------| + | 8 | + +---------------------------+ MONTHNAME @@ -753,11 +753,11 @@ Example:: od> SELECT QUARTER(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +-----------------------------+ - | QUARTER(DATE('2020-08-26')) | - |-----------------------------| - | 3 | - +-----------------------------+ + +----------------------------+ + | QUARTER(DATE('2020-08-26'))| + |----------------------------| + | 3 | + +----------------------------+ From 63ea7885652484a4359bc20303b566043c4b008f Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 10:29:39 -0700 Subject: [PATCH 04/42] fix doctest build error --- docs/user/dql/functions.rst | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index fa041686c8..e7d35ac45c 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -630,11 +630,11 @@ Example:: od> SELECT MONTH(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +---------------------------+ - | MONTH(DATE('2020-08-26')) | - |---------------------------| - | 8 | - +---------------------------+ + +----------------------------+ + | MONTH(DATE('2020-08-26')) | + |----------------------------| + | 8 | + +----------------------------+ MONTHNAME @@ -753,12 +753,11 @@ Example:: od> SELECT QUARTER(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------+ - | QUARTER(DATE('2020-08-26'))| - |----------------------------| - | 3 | - +----------------------------+ - + +------------------------------+ + | QUARTER(DATE('2020-08-26')) | + |------------------------------| + | 3 | + +------------------------------+ RADIANS From 7551dc897aaf94951154b6a4ec032b320463df99 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 10:39:32 -0700 Subject: [PATCH 05/42] fix doctest --- docs/user/dql/functions.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index e7d35ac45c..8856dfba3f 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -630,11 +630,11 @@ Example:: od> SELECT MONTH(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------+ - | MONTH(DATE('2020-08-26')) | - |----------------------------| - | 8 | - +----------------------------+ + +-----------------------------+ + | MONTH(DATE('2020-08-26')) | + |-----------------------------| + | 8 | + +-----------------------------+ MONTHNAME @@ -753,11 +753,11 @@ Example:: od> SELECT QUARTER(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +------------------------------+ - | QUARTER(DATE('2020-08-26')) | - |------------------------------| - | 3 | - +------------------------------+ + +-------------------------------+ + | QUARTER(DATE('2020-08-26')) | + |-------------------------------| + | 3 | + +-------------------------------+ RADIANS From a673fe24b001bcea01f3eae3a887c8245f57f108 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 11:56:39 -0700 Subject: [PATCH 06/42] add dayofmonth() --- docs/user/dql/functions.rst | 20 ++++++++++++++++++-- ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 8856dfba3f..1a7069c0f6 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -335,6 +335,8 @@ Argument type: DATE Return type: INTEGER +Synonyms: DAYOFMONTH + Example:: od> SELECT DAY(DATE('2020-08-26')) @@ -352,9 +354,23 @@ DAYOFMONTH Description ----------- -Specifications: +Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero day part. + +Argument type: DATE + +Return type: INTEGER + +Synonyms: DAY -1. DAYOFMONTH(DATE) -> INTEGER +Example:: + + od> SELECT DAYOFMONTH(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------------+ + | DAYOFMONTH(DATE('2020-08-26')) | + |----------------------------------| + | 26 | + +----------------------------------+ DEGREES diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index 0cccadab13..efd6123718 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -198,6 +198,7 @@ TAN: 'TAN'; DATE: 'DATE'; TIME: 'TIME'; TIMESTAMP: 'TIMESTAMP'; +DAYOFMONTH: 'DAYOFMONTH'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 749ce877eb..c7ff9ec0da 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYOFMONTH | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase From 7c70c3360c055783b48c6c9d6ef5d8670713710f Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 12:30:37 -0700 Subject: [PATCH 07/42] add dayofyear() --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 21 ++++++++++++++++- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 17 ++++++++++++-- docs/user/dql/functions.rst | 23 +++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 9 files changed, 67 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 694563d21e..17732a3486 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -244,6 +244,10 @@ public FunctionExpression dayofmonth(Expression... expressions) { return function(BuiltinFunctionName.DAYOFMONTH, expressions); } + public FunctionExpression dayofyear(Expression... expressions) { + return function(BuiltinFunctionName.DAYOFYEAR, expressions); + } + public FunctionExpression day(Expression... expressions) { return function(BuiltinFunctionName.DAY, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 76a6aa7969..840cb16c99 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -37,7 +37,6 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; -import com.sun.tools.javac.comp.Lower; import lombok.experimental.UtilityClass; /** @@ -55,6 +54,7 @@ public class DateTimeFunction { public void register(BuiltinFunctionRepository repository) { repository.register(date()); repository.register(dayOfMonth()); + repository.register(dayOfYear()); repository.register(time()); repository.register(timestamp()); repository.register(day()); @@ -86,6 +86,16 @@ private FunctionResolver dayOfMonth() { ); } + /** + * DAYOFYEAR(DATE). return the day of the year for date (1-366). + */ + private FunctionResolver dayOfYear() { + return define(BuiltinFunctionName.DAYOFYEAR.getName(), + impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), + INTEGER, DATE) + ); + } + /** * DAY(DATE). return the day of the month (1-31). */ @@ -205,6 +215,15 @@ private ExprValue exprDayOfMonth(ExprValue date) { return new ExprIntegerValue(date.dateValue().getDayOfMonth()); } + /** + * Day of Year implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprDayOfYear(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getDayOfYear()); + } + /** * Time implementation for ExprValue. * @param exprValue ExprValue of Time type or String. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index d4d7336a74..79c1d60a17 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -53,6 +53,7 @@ public enum BuiltinFunctionName { */ DATE(FunctionName.of("date")), DAYOFMONTH(FunctionName.of("dayofmonth")), + DAYOFYEAR(FunctionName.of("dayofyear")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), DAY(FunctionName.of("day")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 6f9c44e69f..5871b7914e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -74,6 +74,19 @@ public void dayOfMonth() { assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); } + @Test + public void dayOfYear() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.dayofyear(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofyear(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(220), eval(expression)); + assertEquals(nullValue(), eval(dsl.dayofyear(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofyear(missingRef))); + } + @Test public void day() { when(nullRef.type()).thenReturn(DATE); @@ -96,8 +109,8 @@ public void month() { assertEquals(INTEGER, expression.type()); assertEquals("month(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(8), eval(expression)); - assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); - assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); + assertEquals(nullValue(), eval(dsl.month(nullRef))); + assertEquals(missingValue(), eval(dsl.month(missingRef))); } @Test diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 1a7069c0f6..4b5be8e7af 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -373,6 +373,29 @@ Example:: +----------------------------------+ +DAYOFYEAR +========== + +Description +----------- + +Usage: dayofyear(date) returns the day of the year for date, in the range 1 to 366. + +Argument type: DATE + +Return type: INTEGER + +Example:: + + od> SELECT DAYOFYEAR(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +---------------------------------+ + | DAYOFYEAR(DATE('2020-08-26')) | + |---------------------------------| + | 239 | + +---------------------------------+ + + DEGREES ======= diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index efd6123718..ed6ce44aec 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -199,6 +199,7 @@ DATE: 'DATE'; TIME: 'TIME'; TIMESTAMP: 'TIMESTAMP'; DAYOFMONTH: 'DAYOFMONTH'; +DAYOFYEAR: 'DAYOFYEAR'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index c7ff9ec0da..e833ddfdc6 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYOFMONTH | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYOFMONTH | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index c672249285..61c303ef96 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -174,6 +174,7 @@ CURDATE: 'CURDATE'; DATE: 'DATE'; DATE_FORMAT: 'DATE_FORMAT'; DAYOFMONTH: 'DAYOFMONTH'; +DAYOFYEAR: 'DAYOFYEAR'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index bda1ed2b61..b3bb64bb33 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYOFMONTH | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYOFMONTH | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From d87f8f4d7228a54b28b4c81413a36f71bf660935 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 12:55:24 -0700 Subject: [PATCH 08/42] add dayofweek() --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 20 ++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + docs/user/dql/functions.rst | 23 +++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 8 files changed, 52 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 17732a3486..dffce6503f 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -244,6 +244,10 @@ public FunctionExpression dayofmonth(Expression... expressions) { return function(BuiltinFunctionName.DAYOFMONTH, expressions); } + public FunctionExpression dayofweek(Expression... expressions) { + return function(BuiltinFunctionName.DAYOFWEEK, expressions); + } + public FunctionExpression dayofyear(Expression... expressions) { return function(BuiltinFunctionName.DAYOFYEAR, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 840cb16c99..07408fa346 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -54,6 +54,7 @@ public class DateTimeFunction { public void register(BuiltinFunctionRepository repository) { repository.register(date()); repository.register(dayOfMonth()); + repository.register(dayOfWeek()); repository.register(dayOfYear()); repository.register(time()); repository.register(timestamp()); @@ -86,6 +87,16 @@ private FunctionResolver dayOfMonth() { ); } + /** + * DAYOFWEEK(DATE). return the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). + */ + private FunctionResolver dayOfWeek() { + return define(BuiltinFunctionName.DAYOFWEEK.getName(), + impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), + INTEGER, DATE) + ); + } + /** * DAYOFYEAR(DATE). return the day of the year for date (1-366). */ @@ -215,6 +226,15 @@ private ExprValue exprDayOfMonth(ExprValue date) { return new ExprIntegerValue(date.dateValue().getDayOfMonth()); } + /** + * Day of Week implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprDayOfWeek(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getDayOfWeek().getValue()); + } + /** * Day of Year implementation for ExprValue. * @param date ExprValue of Date type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 79c1d60a17..b56dae852c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -53,6 +53,7 @@ public enum BuiltinFunctionName { */ DATE(FunctionName.of("date")), DAYOFMONTH(FunctionName.of("dayofmonth")), + DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 4b5be8e7af..4f97fa19d3 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -372,6 +372,29 @@ Example:: | 26 | +----------------------------------+ +DAYOFWEEK +========== + +Description +----------- + +Usage: dayofweek(date) returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). + +Argument type: DATE + +Return type: INTEGER + +Example:: + + od> SELECT DAYOFWEEK(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +----------------------------------+ + | DAYOFWEEK(DATE('2020-08-26')) | + |----------------------------------| + | 4 | + +----------------------------------+ + + DAYOFYEAR ========== diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index ed6ce44aec..e05109d8c1 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -199,6 +199,7 @@ DATE: 'DATE'; TIME: 'TIME'; TIMESTAMP: 'TIMESTAMP'; DAYOFMONTH: 'DAYOFMONTH'; +DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; // LITERALS AND VALUES diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index e833ddfdc6..e0b5025749 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYOFMONTH | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 61c303ef96..f266886602 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -174,6 +174,7 @@ CURDATE: 'CURDATE'; DATE: 'DATE'; DATE_FORMAT: 'DATE_FORMAT'; DAYOFMONTH: 'DAYOFMONTH'; +DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DEGREES: 'DEGREES'; E: 'E'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index b3bb64bb33..b90686a2c3 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYOFMONTH | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From 242403cd8617f8267d11f53ee0c8367016fde9e7 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 13:20:52 -0700 Subject: [PATCH 09/42] fix dayofweek logic & add unit test --- .../expression/datetime/DateTimeFunction.java | 3 ++- .../datetime/DateTimeFunctionTest.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 07408fa346..b4a29ee1e1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -232,7 +232,8 @@ private ExprValue exprDayOfMonth(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfWeek(ExprValue date) { - return new ExprIntegerValue(date.dateValue().getDayOfWeek().getValue()); + return new ExprIntegerValue(date.dateValue().getDayOfWeek().getValue() == 7 ? 1 + : date.dateValue().getDayOfWeek().getValue() + 1); } /** diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 5871b7914e..98b004693c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -74,6 +74,25 @@ public void dayOfMonth() { assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); } + @Test + public void dayOfWeek() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.dayofweek(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofweek(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(6), eval(expression)); + + expression = dsl.dayofweek(DSL.literal(new ExprDateValue("2020-08-09"))); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofweek(DATE '2020-08-09')", expression.toString()); + assertEquals(integerValue(1), eval(expression)); + + assertEquals(nullValue(), eval(dsl.dayofweek(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofweek(missingRef))); + } + @Test public void dayOfYear() { when(nullRef.type()).thenReturn(DATE); From be7051d2a88dfb3d2f145ffb227b13b05108d0af Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 13:26:06 -0700 Subject: [PATCH 10/42] fix doctest for dayofweek() --- docs/user/dql/functions.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 4f97fa19d3..cc851a4724 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -388,11 +388,11 @@ Example:: od> SELECT DAYOFWEEK(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +----------------------------------+ - | DAYOFWEEK(DATE('2020-08-26')) | - |----------------------------------| - | 4 | - +----------------------------------+ + +---------------------------------+ + | DAYOFWEEK(DATE('2020-08-26')) | + |---------------------------------| + | 4 | + +---------------------------------+ From 6834c1079ecf99f2c8612d4e050be8e12c8e17c7 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 16:07:28 -0700 Subject: [PATCH 11/42] add dayname --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 24 +++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 15 ++++++++++++ docs/user/dql/functions.rst | 21 ++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 9 files changed, 69 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index dffce6503f..b62d808d61 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -240,6 +240,10 @@ public FunctionExpression multiply(Expression... expressions) { return function(BuiltinFunctionName.MULTIPLY, expressions); } + public FunctionExpression dayname(Expression... expressions) { + return function(BuiltinFunctionName.DAYNAME, expressions); + } + public FunctionExpression dayofmonth(Expression... expressions) { return function(BuiltinFunctionName.DAYOFMONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index b4a29ee1e1..7fd002274c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -37,6 +37,8 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; +import java.time.format.TextStyle; +import java.util.Locale; import lombok.experimental.UtilityClass; /** @@ -53,6 +55,7 @@ public class DateTimeFunction { */ public void register(BuiltinFunctionRepository repository) { repository.register(date()); + repository.register(dayName()); repository.register(dayOfMonth()); repository.register(dayOfWeek()); repository.register(dayOfYear()); @@ -77,6 +80,17 @@ private FunctionResolver date() { impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP)); } + /** + * DAYNAME(DATE). return the name of the weekday for date, including Monday, Tuesday, Wednesday, + * Thursday, Friday, Saturday and Sunday. + */ + private FunctionResolver dayName() { + return define(BuiltinFunctionName.DAYNAME.getName(), + impl(nullMissingHandling(DateTimeFunction::exprDayName), + STRING, DATE) + ); + } + /** * DAYOFMONTH(DATE). return the day of the month (1-31). */ @@ -217,6 +231,16 @@ private ExprValue exprYear(ExprValue date) { return new ExprIntegerValue(date.dateValue().getYear()); } + /** + * Name of the Weekday implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprDayName(ExprValue date) { + return new ExprStringValue( + date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); + } + /** * Day of Month implementation for ExprValue. * @param date ExprValue of Date type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index b56dae852c..068ac2483d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -52,6 +52,7 @@ public enum BuiltinFunctionName { * Date and Time Functions. */ DATE(FunctionName.of("date")), + DAYNAME(FunctionName.of("dayname")), DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 98b004693c..f40b4ee0e7 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -20,9 +20,11 @@ import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.missingValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.nullValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.stringValue; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -61,6 +63,19 @@ public void setup() { when(missingRef.valueOf(env)).thenReturn(missingValue()); } + @Test + public void dayName() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.dayname(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(STRING, expression.type()); + assertEquals("dayname(DATE '2020-08-07')", expression.toString()); + assertEquals(stringValue("Friday"), eval(expression)); + assertEquals(nullValue(), eval(dsl.dayname(nullRef))); + assertEquals(missingValue(), eval(dsl.dayname(missingRef))); + } + @Test public void dayOfMonth() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index cc851a4724..4132b226af 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -347,6 +347,27 @@ Example:: | 26 | +---------------------------+ +DAYNAME +========== + +Description +----------- + +Usage: dayname(date) returns the name of the weekday for date, including Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. + +Argument type: DATE + +Return type: STRING + +Example:: + + od> SELECT DAYNAME(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +-------------------------------+ + | DAYNAME(DATE('2020-08-26')) | + |-------------------------------| + | Wednesday | + +-------------------------------+ DAYOFMONTH ========== diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index e05109d8c1..cfe4f11c95 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -201,6 +201,7 @@ TIMESTAMP: 'TIMESTAMP'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; +DAYNAME: 'DAYNAME'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index e0b5025749..ba1a00c92e 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index f266886602..629bd45131 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -176,6 +176,7 @@ DATE_FORMAT: 'DATE_FORMAT'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; +DAYNAME: 'DAYNAME'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index b90686a2c3..cc636ec411 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From ee02527085dbbe578c6549d0cd2f024fbe5f7c5e Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 17:49:27 -0700 Subject: [PATCH 12/42] add monthname --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 20 +++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 13 ++++++++++++ docs/user/dql/functions.rst | 17 +++++++++++++--- ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 9 files changed, 56 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index b62d808d61..041598e183 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -244,6 +244,10 @@ public FunctionExpression dayname(Expression... expressions) { return function(BuiltinFunctionName.DAYNAME, expressions); } + public FunctionExpression monthname(Expression... expressions) { + return function(BuiltinFunctionName.MONTHNAME, expressions); + } + public FunctionExpression dayofmonth(Expression... expressions) { return function(BuiltinFunctionName.DAYOFMONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 7fd002274c..9cd8b5f88e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -56,6 +56,7 @@ public class DateTimeFunction { public void register(BuiltinFunctionRepository repository) { repository.register(date()); repository.register(dayName()); + repository.register(monthName()); repository.register(dayOfMonth()); repository.register(dayOfWeek()); repository.register(dayOfYear()); @@ -91,6 +92,16 @@ private FunctionResolver dayName() { ); } + /** + * MONTHNAME(DATE). return the full name of the month for date. + */ + private FunctionResolver monthName() { + return define(BuiltinFunctionName.MONTHNAME.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMonthName), + STRING, DATE) + ); + } + /** * DAYOFMONTH(DATE). return the day of the month (1-31). */ @@ -241,6 +252,15 @@ private ExprValue exprDayName(ExprValue date) { date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); } + /** + * Name of the Month implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprMonthName(ExprValue date) { + return new ExprStringValue(date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); + } + /** * Day of Month implementation for ExprValue. * @param date ExprValue of Date type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 068ac2483d..a07d20d4cf 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -53,6 +53,7 @@ public enum BuiltinFunctionName { */ DATE(FunctionName.of("date")), DAYNAME(FunctionName.of("dayname")), + MONTHNAME(FunctionName.of("monthname")), DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index f40b4ee0e7..4f2d761fc9 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -76,6 +76,19 @@ public void dayName() { assertEquals(missingValue(), eval(dsl.dayname(missingRef))); } + @Test + public void monthName() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.monthname(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(STRING, expression.type()); + assertEquals("monthname(DATE '2020-08-07')", expression.toString()); + assertEquals(stringValue("August"), eval(expression)); + assertEquals(nullValue(), eval(dsl.monthname(nullRef))); + assertEquals(missingValue(), eval(dsl.monthname(missingRef))); + } + @Test public void dayOfMonth() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 4132b226af..2dc8a7910d 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -721,14 +721,25 @@ Example:: MONTHNAME -========= Description ----------- -Specifications: +Usage: monthname(date) returns the full name of the month for date. + +Argument type: DATE + +Return type: STRING -1. MONTHNAME(DATE) -> STRING +Example:: + + od> SELECT MONTHNAME(DATE('2020-08-26')) + fetched rows / total rows = 1/1 + +-------------------------------+ + | MONTHNAME(DATE('2020-08-26')) | + |-------------------------------| + | August | + +-------------------------------+ MULTIPLY diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index cfe4f11c95..977658d4f3 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -202,6 +202,7 @@ DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; +MONTHNAME: 'MONTHNAME'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index ba1a00c92e..68de36b944 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 629bd45131..b61d89d7b7 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -177,6 +177,7 @@ DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; +MONTHNAME: 'MONTHNAME'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index cc636ec411..f1641d2b56 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From 8ab2f631839328f579ec4fd560edf209353b0c63 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 9 Sep 2020 17:52:57 -0700 Subject: [PATCH 13/42] fix checkstyle build error --- .../sql/expression/datetime/DateTimeFunction.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 9cd8b5f88e..18da46764c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -258,7 +258,8 @@ private ExprValue exprDayName(ExprValue date) { * @return ExprValue. */ private ExprValue exprMonthName(ExprValue date) { - return new ExprStringValue(date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); + return new ExprStringValue( + date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); } /** From 458c34a7dd4b5467739a3f0db8df60ecb1ba1661 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 10 Sep 2020 09:32:44 -0700 Subject: [PATCH 14/42] fix build error --- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index b61d89d7b7..629bd45131 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -177,7 +177,6 @@ DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; -MONTHNAME: 'MONTHNAME'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; From e42aac16068445331a00ec4eded4666274722448 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 10 Sep 2020 09:40:15 -0700 Subject: [PATCH 15/42] fix doctest for monthname --- docs/user/dql/functions.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 2dc8a7910d..2a637a00f0 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -735,11 +735,11 @@ Example:: od> SELECT MONTHNAME(DATE('2020-08-26')) fetched rows / total rows = 1/1 - +-------------------------------+ - | MONTHNAME(DATE('2020-08-26')) | - |-------------------------------| - | August | - +-------------------------------+ + +---------------------------------+ + | MONTHNAME(DATE('2020-08-26')) | + |---------------------------------| + | August | + +---------------------------------+ MULTIPLY From 960783bc9a08cbd67ccb379d40cac86435767152 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 10 Sep 2020 10:50:16 -0700 Subject: [PATCH 16/42] add hour() --- .../sql/expression/DSL.java | 4 +++ .../expression/datetime/DateTimeFunction.java | 24 ++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 23 +++++++++++++++++ docs/user/dql/functions.rst | 25 ++++++++++++++++++- ppl/src/main/antlr/OpenDistroPPLParser.g4 | 3 ++- sql/src/main/antlr/OpenDistroSQLParser.g4 | 3 ++- 7 files changed, 80 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 041598e183..34faf66ac6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -264,6 +264,10 @@ public FunctionExpression day(Expression... expressions) { return function(BuiltinFunctionName.DAY, expressions); } + public FunctionExpression hour(Expression... expressions) { + return function(BuiltinFunctionName.HOUR, expressions); + } + public FunctionExpression month(Expression... expressions) { return function(BuiltinFunctionName.MONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 18da46764c..57cd22f9aa 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -60,6 +60,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(dayOfMonth()); repository.register(dayOfWeek()); repository.register(dayOfYear()); + repository.register(hour()); repository.register(time()); repository.register(timestamp()); repository.register(day()); @@ -142,6 +143,20 @@ private FunctionResolver day() { ); } + /** + * HOUR(TIME). return the hour value for time. + */ + private FunctionResolver hour() { + return define(BuiltinFunctionName.HOUR.getName(), + impl(nullMissingHandling(DateTimeFunction::exprHour), + INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprHour), + INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprHour), + INTEGER, TIMESTAMP) + ); + } + /** * MONTH(DATE). return the month for date (1-12). */ @@ -290,6 +305,15 @@ private ExprValue exprDayOfYear(ExprValue date) { return new ExprIntegerValue(date.dateValue().getDayOfYear()); } + /** + * Hour implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprHour(ExprValue exprValue) { + return new ExprIntegerValue(exprValue.timeValue().getHour()); + } + /** * Time implementation for ExprValue. * @param exprValue ExprValue of Time type or String. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index a07d20d4cf..6cde26116f 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -57,6 +57,7 @@ public enum BuiltinFunctionName { DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), + HOUR(FunctionName.of("hour")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), DAY(FunctionName.of("day")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 4f2d761fc9..2da238b21e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -147,6 +147,29 @@ public void day() { assertEquals(missingValue(), eval(dsl.day(missingRef))); } + @Test + public void hour() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.hour(nullRef))); + assertEquals(missingValue(), eval(dsl.hour(missingRef))); + + FunctionExpression expression = dsl.hour(DSL.literal(new ExprTimeValue("01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(1), eval(expression)); + assertEquals("hour(TIME '01:02:03')", expression.toString()); + + expression = dsl.hour(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(1), expression.valueOf(env)); + assertEquals("hour(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.hour(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(1), expression.valueOf(env)); + assertEquals("hour(DATETIME '2020-08-17 01:02:03')", expression.toString()); + } + @Test public void month() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 2a637a00f0..4b670100bc 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -523,11 +523,34 @@ FLOOR Description ----------- -Specifications: +Specifications: 1. FLOOR(NUMBER T) -> T +HOUR +===== + +Description +----------- + +Usage: hour(time) extracts the hour value for time. Different from the time of day value, the time value has a large range and can be greater than 23, so the return value of hour(time) can be also greater than 23. + +Argument type: TIME + +Return type: INTEGER + +Example:: + + od> SELECT HOUR((TIME '01:02:03')) + fetched rows / total rows = 1/1 + +---------------------------+ + | HOUR((TIME '01:02:03')) | + |---------------------------| + | 1 | + +---------------------------+ + + IF == diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 68de36b944..78cb031640 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,8 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : HOUR | DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index f1641d2b56..79b6a78ee8 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,7 +211,8 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : HOUR | DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR ; functionArgs From 4d355b22b380b9358a6c161e64ef2ed2bded2702 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 10 Sep 2020 15:30:54 -0700 Subject: [PATCH 17/42] add minute() --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 24 +++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 23 ++++++++++++++++++ docs/user/dql/functions.rst | 23 ++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLParser.g4 | 4 ++-- sql/src/main/antlr/OpenDistroSQLParser.g4 | 4 ++-- 7 files changed, 79 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 34faf66ac6..a38d05b943 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -268,6 +268,10 @@ public FunctionExpression hour(Expression... expressions) { return function(BuiltinFunctionName.HOUR, expressions); } + public FunctionExpression minute(Expression... expressions) { + return function(BuiltinFunctionName.MINUTE, expressions); + } + public FunctionExpression month(Expression... expressions) { return function(BuiltinFunctionName.MONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 57cd22f9aa..ec449e8107 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -61,6 +61,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(dayOfWeek()); repository.register(dayOfYear()); repository.register(hour()); + repository.register(minute()); repository.register(time()); repository.register(timestamp()); repository.register(day()); @@ -157,6 +158,20 @@ private FunctionResolver hour() { ); } + /** + * MINUTE(TIME). return the minute value for time. + */ + private FunctionResolver minute() { + return define(BuiltinFunctionName.MINUTE.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMinute), + INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprMinute), + INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMinute), + INTEGER, TIMESTAMP) + ); + } + /** * MONTH(DATE). return the month for date (1-12). */ @@ -314,6 +329,15 @@ private ExprValue exprHour(ExprValue exprValue) { return new ExprIntegerValue(exprValue.timeValue().getHour()); } + /** + * Minute implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprMinute(ExprValue exprValue) { + return new ExprIntegerValue(exprValue.timeValue().getMinute()); + } + /** * Time implementation for ExprValue. * @param exprValue ExprValue of Time type or String. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 6cde26116f..1eda924db9 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -58,6 +58,7 @@ public enum BuiltinFunctionName { DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), HOUR(FunctionName.of("hour")), + MINUTE(FunctionName.of("minute")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), DAY(FunctionName.of("day")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 2da238b21e..4e589d450a 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -170,6 +170,29 @@ public void hour() { assertEquals("hour(DATETIME '2020-08-17 01:02:03')", expression.toString()); } + @Test + public void minute() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.minute(nullRef))); + assertEquals(missingValue(), eval(dsl.minute(missingRef))); + + FunctionExpression expression = dsl.minute(DSL.literal(new ExprTimeValue("01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), eval(expression)); + assertEquals("minute(TIME '01:02:03')", expression.toString()); + + expression = dsl.minute(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), expression.valueOf(env)); + assertEquals("minute(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.minute(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), expression.valueOf(env)); + assertEquals("minute(DATETIME '2020-08-17 01:02:03')", expression.toString()); + } + @Test public void month() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 4b670100bc..c50ef6176a 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -720,6 +720,29 @@ Example:: +-------------+---------------+ +MINUTE +===== + +Description +----------- + +Usage: minute(time) returns the minute for time, in the range 0 to 59. + +Argument type: TIME + +Return type: INTEGER + +Example:: + + od> SELECT MINUTE((TIME '01:02:03')) + fetched rows / total rows = 1/1 + +-----------------------------+ + | MINUTE((TIME '01:02:03')) | + |-----------------------------| + | 2 | + +-----------------------------+ + + MONTH ===== diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 78cb031640..7ecd6cb2f0 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,8 +226,8 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : HOUR | DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index 79b6a78ee8..9e50a92a22 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,8 +211,8 @@ trigonometricFunctionName ; dateTimeFunctionName - : HOUR | DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR + : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE ; functionArgs From 0881f24b02e2e493d56775731462c77623291ea1 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Fri, 11 Sep 2020 15:00:54 -0700 Subject: [PATCH 18/42] add second --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 24 +++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 23 ++++++++++++++++++ docs/user/dql/functions.rst | 23 ++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 7 files changed, 77 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index a38d05b943..1ea2572d29 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -272,6 +272,10 @@ public FunctionExpression minute(Expression... expressions) { return function(BuiltinFunctionName.MINUTE, expressions); } + public FunctionExpression second(Expression... expressions) { + return function(BuiltinFunctionName.SECOND, expressions); + } + public FunctionExpression month(Expression... expressions) { return function(BuiltinFunctionName.MONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index ec449e8107..061f6fa748 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -62,6 +62,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(dayOfYear()); repository.register(hour()); repository.register(minute()); + repository.register(second()); repository.register(time()); repository.register(timestamp()); repository.register(day()); @@ -172,6 +173,20 @@ private FunctionResolver minute() { ); } + /** + * SECOND(TIME). return the second value for time. + */ + private FunctionResolver second() { + return define(BuiltinFunctionName.SECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, TIMESTAMP) + ); + } + /** * MONTH(DATE). return the month for date (1-12). */ @@ -338,6 +353,15 @@ private ExprValue exprMinute(ExprValue exprValue) { return new ExprIntegerValue(exprValue.timeValue().getMinute()); } + /** + * Second implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprSecond(ExprValue exprValue) { + return new ExprIntegerValue(exprValue.timeValue().getSecond()); + } + /** * Time implementation for ExprValue. * @param exprValue ExprValue of Time type or String. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 1eda924db9..06bb093b2e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -59,6 +59,7 @@ public enum BuiltinFunctionName { DAYOFYEAR(FunctionName.of("dayofyear")), HOUR(FunctionName.of("hour")), MINUTE(FunctionName.of("minute")), + SECOND(FunctionName.of("second")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), DAY(FunctionName.of("day")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 4e589d450a..7b6baa94f0 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -193,6 +193,29 @@ public void minute() { assertEquals("minute(DATETIME '2020-08-17 01:02:03')", expression.toString()); } + @Test + public void second() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.second(nullRef))); + assertEquals(missingValue(), eval(dsl.second(missingRef))); + + FunctionExpression expression = dsl.second(DSL.literal(new ExprTimeValue("01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), eval(expression)); + assertEquals("second(TIME '01:02:03')", expression.toString()); + + expression = dsl.second(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), expression.valueOf(env)); + assertEquals("second(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.second(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), expression.valueOf(env)); + assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); + } + @Test public void month() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index c50ef6176a..5cdcc5b55a 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1016,6 +1016,29 @@ Specifications: 1. RTRIM(STRING T) -> T +SECOND +===== + +Description +----------- + +Usage: second(time) returns the second for time, in the range 0 to 59. + +Argument type: TIME + +Return type: INTEGER + +Example:: + + od> SELECT SECOND((TIME '01:02:03')) + fetched rows / total rows = 1/1 + +-----------------------------+ + | SECOND((TIME '01:02:03')) | + |-----------------------------| + | 3 | + +-----------------------------+ + + SIGN ==== diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 7ecd6cb2f0..2474a991c7 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -227,7 +227,7 @@ trigonometricFunctionName dateAndTimeFunctionBase : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index 9e50a92a22..e6b6ecfdd5 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -212,7 +212,7 @@ trigonometricFunctionName dateTimeFunctionName : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND ; functionArgs From d199d5422fcf00939d03871457ccb67032c08a0e Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Mon, 14 Sep 2020 12:47:24 -0700 Subject: [PATCH 19/42] add microsecond --- .../sql/expression/DSL.java | 4 ++ .../expression/datetime/DateTimeFunction.java | 27 +++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 30 ++++++++++++ docs/user/dql/functions.rst | 46 ++++++++++++++----- ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 7 files changed, 99 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 1ea2572d29..9d7aff3190 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -276,6 +276,10 @@ public FunctionExpression second(Expression... expressions) { return function(BuiltinFunctionName.SECOND, expressions); } + public FunctionExpression microsecond(Expression... expressions) { + return function(BuiltinFunctionName.MICROSECOND, expressions); + } + public FunctionExpression month(Expression... expressions) { return function(BuiltinFunctionName.MONTH, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 061f6fa748..660c689005 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -37,6 +37,7 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; +import com.google.common.base.CharMatcher; import java.time.format.TextStyle; import java.util.Locale; import lombok.experimental.UtilityClass; @@ -63,6 +64,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(hour()); repository.register(minute()); repository.register(second()); + repository.register(microsecond()); repository.register(time()); repository.register(timestamp()); repository.register(day()); @@ -187,6 +189,20 @@ private FunctionResolver second() { ); } + /** + * MICROSECOND(TIME). return the microsecond value for time. + */ + private FunctionResolver microsecond() { + return define(BuiltinFunctionName.MICROSECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + INTEGER, TIMESTAMP) + ); + } + /** * MONTH(DATE). return the month for date (1-12). */ @@ -362,6 +378,17 @@ private ExprValue exprSecond(ExprValue exprValue) { return new ExprIntegerValue(exprValue.timeValue().getSecond()); } + /** + * Microsecond implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprMicrosecond(ExprValue exprValue) { + return new ExprIntegerValue((exprValue.timeValue().getNano() == 0) ? 0 + : Integer.parseInt(CharMatcher.is('0') + .trimTrailingFrom(Integer.toString(exprValue.timeValue().getNano())))); + } + /** * Time implementation for ExprValue. * @param exprValue ExprValue of Time type or String. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 06bb093b2e..d2c4a28685 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -60,6 +60,7 @@ public enum BuiltinFunctionName { HOUR(FunctionName.of("hour")), MINUTE(FunctionName.of("minute")), SECOND(FunctionName.of("second")), + MICROSECOND(FunctionName.of("microsecond")), TIME(FunctionName.of("time")), TIMESTAMP(FunctionName.of("timestamp")), DAY(FunctionName.of("day")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 7b6baa94f0..0994a644cc 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -216,6 +216,36 @@ public void second() { assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); } + @Test + public void microsecond() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.microsecond(nullRef))); + assertEquals(missingValue(), eval(dsl.microsecond(missingRef))); + + FunctionExpression expression = dsl + .microsecond(DSL.literal(new ExprTimeValue("01:02:03.123456"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(123456), eval(expression)); + assertEquals("microsecond(TIME '01:02:03.123456')", expression.toString()); + + expression = dsl.microsecond(DSL.literal(new ExprTimeValue("01:02:03.00"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(0), eval(expression)); + assertEquals("microsecond(TIME '01:02:03')", expression.toString()); + + /* + expression = dsl.microsecond(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03.123456"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(123456), expression.valueOf(env)); + assertEquals("microsecond(TIMESTAMP '2020-08-17 01:02:03.123456')", expression.toString()); + + expression = dsl.microsecond(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03.123456"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(123456), expression.valueOf(env)); + assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString());*/ + } + @Test public void month() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 5cdcc5b55a..c62e284893 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -697,27 +697,27 @@ Specifications: 1. MAKETIME(INTEGER, INTEGER, INTEGER) -> DATE -MOD -======= +MICROSECOND +===== Description ----------- -Usage: MOD(n, m) calculates the remainder of the number n divided by m. +Usage: microsecond(expr) returns the microseconds from the time or datetime expression expr as a number in the range from 0 to 999999. -Argument type: INTEGER/LONG/FLOAT/DOUBLE +Argument type: TIME -Return type: Wider type between types of n and m if m is nonzero value. If m equals to 0, then returns NULL. +Return type: INTEGER Example:: - od> SELECT MOD(3, 2), MOD(3.1, 2) + od> SELECT MICROSECOND((TIME '01:02:03.123456')) fetched rows / total rows = 1/1 - +-------------+---------------+ - | MOD(3, 2) | MOD(3.1, 2) | - |-------------+---------------| - | 1 | 1.1 | - +-------------+---------------+ + +-----------------------------------------+ + | MICROSECOND((TIME '01:02:03.123456')) | + |-----------------------------------------| + | 123456 | + +-----------------------------------------+ MINUTE @@ -743,6 +743,30 @@ Example:: +-----------------------------+ +MOD +======= + +Description +----------- + +Usage: MOD(n, m) calculates the remainder of the number n divided by m. + +Argument type: INTEGER/LONG/FLOAT/DOUBLE + +Return type: Wider type between types of n and m if m is nonzero value. If m equals to 0, then returns NULL. + +Example:: + + od> SELECT MOD(3, 2), MOD(3.1, 2) + fetched rows / total rows = 1/1 + +-------------+---------------+ + | MOD(3, 2) | MOD(3.1, 2) | + |-------------+---------------| + | 1 | 1.1 | + +-------------+---------------+ + + + MONTH ===== diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 2474a991c7..6fdf89cb56 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -227,7 +227,7 @@ trigonometricFunctionName dateAndTimeFunctionBase : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index e6b6ecfdd5..d5fa0aee8a 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -212,7 +212,7 @@ trigonometricFunctionName dateTimeFunctionName : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND + | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND ; functionArgs From c88a6dd38c69fa8fd22db5b17d9c7233363bbc3a Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Mon, 14 Sep 2020 17:35:09 -0700 Subject: [PATCH 20/42] fix datetime & timestamp issue for microsecond --- .../sql/data/model/ExprDatetimeValue.java | 12 ++++++++---- .../sql/data/model/ExprTimestampValue.java | 8 ++++++-- .../sql/data/model/DateTimeValueTest.java | 5 +++-- .../expression/datetime/DateTimeFunctionTest.java | 3 +-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java index e932e6ca5d..4ed25e6dcb 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java @@ -27,12 +27,13 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class ExprDatetimeValue extends AbstractExprValue { private static final DateTimeFormatter formatter = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss"); + .ofPattern("yyyy-MM-dd HH:mm:ss[.SSSSSS]"); private final LocalDateTime datetime; /** @@ -43,7 +44,7 @@ public ExprDatetimeValue(String datetime) { this.datetime = LocalDateTime.parse(datetime, formatter); } catch (DateTimeParseException e) { throw new SemanticCheckException(String.format("datetime:%s in unsupported format, please " - + "use yyyy-MM-dd HH:mm:ss", datetime)); + + "use yyyy-MM-dd HH:mm:ss[.SSSSSS]", datetime)); } } @@ -79,8 +80,11 @@ public boolean equal(ExprValue other) { @Override public String value() { - return String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), - DateTimeFormatter.ISO_TIME.format(datetime)); + return datetime.getNano() == 0 + ? String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), + DateTimeFormatter.ISO_TIME.format(datetime.truncatedTo(ChronoUnit.SECONDS))) + : String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), + DateTimeFormatter.ISO_TIME.format(datetime)); } @Override diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java index dbc40dd133..a3dda267d0 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java @@ -44,6 +44,8 @@ public class ExprTimestampValue extends AbstractExprValue { * todo. only support timestamp in format yyyy-MM-dd HH:mm:ss. */ private static final DateTimeFormatter FORMATTER = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss[.n]"); + private static final DateTimeFormatter FORMATTER_WITNOUT_NANO = DateTimeFormatter .ofPattern("yyyy-MM-dd HH:mm:ss"); private final Instant timestamp; @@ -55,14 +57,16 @@ public ExprTimestampValue(String timestamp) { this.timestamp = LocalDateTime.parse(timestamp, FORMATTER).atZone(ZONE).toInstant(); } catch (DateTimeParseException e) { throw new SemanticCheckException(String.format("timestamp:%s in unsupported format, please " - + "use yyyy-MM-dd HH:mm:ss", timestamp)); + + "use yyyy-MM-dd HH:mm:ss[.n]", timestamp)); } } @Override public String value() { - return FORMATTER.withZone(ZONE).format(timestamp.truncatedTo(ChronoUnit.SECONDS)); + return timestamp.getNano() == 0 ? FORMATTER_WITNOUT_NANO.withZone(ZONE) + .format(timestamp.truncatedTo(ChronoUnit.SECONDS)) + : FORMATTER.withZone(ZONE).format(timestamp); } @Override diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java index e77936dc25..470bacabdb 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java @@ -113,7 +113,7 @@ public void timestampInUnsupportedFormat() { assertThrows(SemanticCheckException.class, () -> new ExprTimestampValue("2020-07-07T01:01:01Z")); assertEquals( - "timestamp:2020-07-07T01:01:01Z in unsupported format, please use yyyy-MM-dd HH:mm:ss", + "timestamp:2020-07-07T01:01:01Z in unsupported format, please use yyyy-MM-dd HH:mm:ss[.n]", exception.getMessage()); } @@ -123,7 +123,8 @@ public void datetimeInUnsupportedFormat() { assertThrows(SemanticCheckException.class, () -> new ExprDatetimeValue("2020-07-07T01:01:01Z")); assertEquals( - "datetime:2020-07-07T01:01:01Z in unsupported format, please use yyyy-MM-dd HH:mm:ss", + "datetime:2020-07-07T01:01:01Z in unsupported format, " + + "please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", exception.getMessage()); } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 0994a644cc..e6f226bd64 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -234,7 +234,6 @@ public void microsecond() { assertEquals(integerValue(0), eval(expression)); assertEquals("microsecond(TIME '01:02:03')", expression.toString()); - /* expression = dsl.microsecond(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03.123456"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(123456), expression.valueOf(env)); @@ -243,7 +242,7 @@ public void microsecond() { expression = dsl.microsecond(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03.123456"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(123456), expression.valueOf(env)); - assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString());*/ + assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString()); } @Test From 4dd0db058b446ed1e8a3325c4adea2d8011f0bd0 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 15 Sep 2020 10:30:59 -0700 Subject: [PATCH 21/42] add time_to_sec --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 22 ++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 15 ++++++++++++ docs/user/dql/functions.rst | 23 +++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 1 + sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 1 + 9 files changed, 69 insertions(+) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 9d7aff3190..45b22ea8e5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -292,6 +292,10 @@ public FunctionExpression year(Expression... expressions) { return function(BuiltinFunctionName.YEAR, expressions); } + public FunctionExpression time_to_sec(Expression... expressions) { + return function(BuiltinFunctionName.TIME_TO_SEC, expressions); + } + public FunctionExpression date(Expression... expressions) { return function(BuiltinFunctionName.DATE, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 660c689005..1f6df7ffea 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -21,6 +21,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.LONG; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; @@ -30,6 +31,7 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprIntegerValue; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprLongValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprStringValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; @@ -71,6 +73,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(month()); repository.register(quarter()); repository.register(year()); + repository.register(time_to_sec()); } /** @@ -233,6 +236,16 @@ private FunctionResolver year() { ); } + /** + * TIME_TO_SEC(TIME). return the time argument, converted to seconds. + */ + private FunctionResolver time_to_sec() { + return define(BuiltinFunctionName.TIME_TO_SEC.getName(), + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), + LONG, TIME) + ); + } + /** * Extracts the time part of a date and time value. * Also to construct a time type. The supported signatures: @@ -414,4 +427,13 @@ private ExprValue exprTimestamp(ExprValue exprValue) { return new ExprTimestampValue(exprValue.timestampValue()); } } + + /** + * Time To Sec implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprTimeToSec(ExprValue exprValue) { + return new ExprLongValue(exprValue.timeValue().toSecondOfDay()); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index d2c4a28685..82f3db93cf 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -67,6 +67,7 @@ public enum BuiltinFunctionName { MONTH(FunctionName.of("month")), QUARTER(FunctionName.of("quarter")), YEAR(FunctionName.of("year")), + TIME_TO_SEC(FunctionName.of("time_to_sec")), /** * Text Functions. diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index e6f226bd64..12fdd8579c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -18,12 +18,14 @@ package com.amazon.opendistroforelasticsearch.sql.expression.datetime; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.longValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.missingValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.nullValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.stringValue; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.LONG; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; @@ -290,6 +292,19 @@ public void year() { assertEquals(missingValue(), eval(dsl.year(missingRef))); } + @Test + public void time_to_sec() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.time_to_sec(nullRef))); + assertEquals(missingValue(), eval(dsl.time_to_sec(missingRef))); + + FunctionExpression expression = dsl.time_to_sec(DSL.literal(new ExprTimeValue("22:23:00"))); + assertEquals(LONG, expression.type()); + assertEquals("time_to_sec(TIME '22:23:00')", expression.toString()); + assertEquals(longValue(80580L), eval(expression)); + } + @Test public void date() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index c62e284893..b2f77aff02 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1202,6 +1202,29 @@ Example:: +----------+ +TIME_TO_SEC +=== + +Description +----------- + +Usage: time_to_sec(time) returns the time argument, converted to seconds. + +Argument type: TIME + +Return type: LONG + +Example:: + + od> SELECT time_to_sec(TIME '22:23:00') + fetched rows / total rows = 1/1 + +--------------------------------+ + | time_to_sec(TIME '22:23:00') | + |--------------------------------| + | 80580 | + +--------------------------------+ + + TIMESTAMP ========= diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index 977658d4f3..bf5abb502c 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -203,6 +203,7 @@ DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; MONTHNAME: 'MONTHNAME'; +TIME_TO_SEC: 'TIME_TO_SEC'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 6fdf89cb56..94443add6b 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -228,6 +228,7 @@ trigonometricFunctionName dateAndTimeFunctionBase : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND + | TIME_TO_SEC ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 629bd45131..9c260d58d1 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -177,6 +177,7 @@ DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; +TIME_TO_SEC: 'TIME_TO_SEC'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index d5fa0aee8a..2bef072989 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -213,6 +213,7 @@ trigonometricFunctionName dateTimeFunctionName : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND + | TIME_TO_SEC ; functionArgs From 988d177d507e935a52f4e68a5cbd72da66e0d4b4 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 15 Sep 2020 13:13:32 -0700 Subject: [PATCH 22/42] add subdate & date_sub --- .../sql/expression/DSL.java | 56 ++++++----- .../expression/datetime/DateTimeFunction.java | 80 ++++++++++++++-- .../function/BuiltinFunctionName.java | 14 +-- .../datetime/DateTimeFunctionTest.java | 94 +++++++++++++++++++ docs/user/dql/functions.rst | 54 ++++++++++- ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 6 +- ppl/src/main/antlr/OpenDistroPPLParser.g4 | 5 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 4 +- sql/src/main/antlr/OpenDistroSQLParser.g4 | 5 +- 9 files changed, 270 insertions(+), 48 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 45b22ea8e5..93ed50fb96 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -240,12 +240,20 @@ public FunctionExpression multiply(Expression... expressions) { return function(BuiltinFunctionName.MULTIPLY, expressions); } - public FunctionExpression dayname(Expression... expressions) { - return function(BuiltinFunctionName.DAYNAME, expressions); + public FunctionExpression date(Expression... expressions) { + return function(BuiltinFunctionName.DATE, expressions); } - public FunctionExpression monthname(Expression... expressions) { - return function(BuiltinFunctionName.MONTHNAME, expressions); + public FunctionExpression date_sub(Expression... expressions) { + return function(BuiltinFunctionName.DATE_SUB, expressions); + } + + public FunctionExpression day(Expression... expressions) { + return function(BuiltinFunctionName.DAY, expressions); + } + + public FunctionExpression dayname(Expression... expressions) { + return function(BuiltinFunctionName.DAYNAME, expressions); } public FunctionExpression dayofmonth(Expression... expressions) { @@ -260,54 +268,54 @@ public FunctionExpression dayofyear(Expression... expressions) { return function(BuiltinFunctionName.DAYOFYEAR, expressions); } - public FunctionExpression day(Expression... expressions) { - return function(BuiltinFunctionName.DAY, expressions); - } - public FunctionExpression hour(Expression... expressions) { return function(BuiltinFunctionName.HOUR, expressions); } - public FunctionExpression minute(Expression... expressions) { - return function(BuiltinFunctionName.MINUTE, expressions); - } - - public FunctionExpression second(Expression... expressions) { - return function(BuiltinFunctionName.SECOND, expressions); - } - public FunctionExpression microsecond(Expression... expressions) { return function(BuiltinFunctionName.MICROSECOND, expressions); } + public FunctionExpression minute(Expression... expressions) { + return function(BuiltinFunctionName.MINUTE, expressions); + } + public FunctionExpression month(Expression... expressions) { return function(BuiltinFunctionName.MONTH, expressions); } - public FunctionExpression quarter(Expression... expressions) { - return function(BuiltinFunctionName.QUARTER, expressions); + public FunctionExpression monthname(Expression... expressions) { + return function(BuiltinFunctionName.MONTHNAME, expressions); } - public FunctionExpression year(Expression... expressions) { - return function(BuiltinFunctionName.YEAR, expressions); + public FunctionExpression quarter(Expression... expressions) { + return function(BuiltinFunctionName.QUARTER, expressions); } - public FunctionExpression time_to_sec(Expression... expressions) { - return function(BuiltinFunctionName.TIME_TO_SEC, expressions); + public FunctionExpression second(Expression... expressions) { + return function(BuiltinFunctionName.SECOND, expressions); } - public FunctionExpression date(Expression... expressions) { - return function(BuiltinFunctionName.DATE, expressions); + public FunctionExpression subdate(Expression... expressions) { + return function(BuiltinFunctionName.SUBDATE, expressions); } public FunctionExpression time(Expression... expressions) { return function(BuiltinFunctionName.TIME, expressions); } + public FunctionExpression time_to_sec(Expression... expressions) { + return function(BuiltinFunctionName.TIME_TO_SEC, expressions); + } + public FunctionExpression timestamp(Expression... expressions) { return function(BuiltinFunctionName.TIMESTAMP, expressions); } + public FunctionExpression year(Expression... expressions) { + return function(BuiltinFunctionName.YEAR, expressions); + } + public FunctionExpression divide(Expression... expressions) { return function(BuiltinFunctionName.DIVIDE, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 1f6df7ffea..4893bf46b5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -21,6 +21,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTERVAL; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.LONG; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; @@ -30,6 +31,7 @@ import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionDSL.nullMissingHandling; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDatetimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprIntegerValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprLongValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprStringValue; @@ -58,22 +60,24 @@ public class DateTimeFunction { */ public void register(BuiltinFunctionRepository repository) { repository.register(date()); + repository.register(date_sub()); + repository.register(day()); repository.register(dayName()); - repository.register(monthName()); repository.register(dayOfMonth()); repository.register(dayOfWeek()); repository.register(dayOfYear()); repository.register(hour()); + repository.register(microsecond()); repository.register(minute()); + repository.register(month()); + repository.register(monthName()); + repository.register(quarter()); repository.register(second()); - repository.register(microsecond()); + repository.register(subdate()); repository.register(time()); + repository.register(time_to_sec()); repository.register(timestamp()); - repository.register(day()); - repository.register(month()); - repository.register(quarter()); repository.register(year()); - repository.register(time_to_sec()); } /** @@ -89,6 +93,44 @@ private FunctionResolver date() { impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP)); } + /** + * Extracts the date part of a date and time value. + * Also to construct a date type. The supported signatures: + * STRING/DATE/DATETIME/TIMESTAMP -> DATE + */ + private FunctionResolver date_sub() { + return define(BuiltinFunctionName.DATE_SUB.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, DATETIME, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, TIMESTAMP, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) + ); + } + + /** + * Extracts the date part of a date and time value. + * Also to construct a date type. The supported signatures: + * STRING/DATE/DATETIME/TIMESTAMP -> DATE + */ + private FunctionResolver subdate() { + return define(BuiltinFunctionName.SUBDATE.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, DATETIME, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, TIMESTAMP, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) + ); + } + /** * DAYNAME(DATE). return the name of the weekday for date, including Monday, Tuesday, Wednesday, * Thursday, Friday, Saturday and Sunday. @@ -286,6 +328,32 @@ private ExprValue exprDate(ExprValue exprValue) { } } + /** + * SUBDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param expr ExprValue of Interval type, the temporal amount to subtract. + * @return Date/Datetime resulted from expr subtracted to date. + */ + private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { + return new ExprDatetimeValue(date.datetimeValue().minus(expr.intervalValue())); + } + + /** + * SUBDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param days ExprValue of Long type, representing the number of days to subtract. + * @return Date/Datetime resulted from days subtracted to date. + */ + private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { + if (date instanceof ExprDateValue) { + return new ExprDateValue(date.dateValue().minusDays(days.longValue())); + } else { + return new ExprDatetimeValue(date.datetimeValue().minusDays(days.longValue())); + } + } + /** * Month for date implementation for ExprValue. * @param date ExprValue of Date type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 82f3db93cf..592c53f719 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -52,22 +52,24 @@ public enum BuiltinFunctionName { * Date and Time Functions. */ DATE(FunctionName.of("date")), + DATE_SUB(FunctionName.of("date_sub")), + DAY(FunctionName.of("day")), DAYNAME(FunctionName.of("dayname")), - MONTHNAME(FunctionName.of("monthname")), DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), HOUR(FunctionName.of("hour")), + MICROSECOND(FunctionName.of("microsecond")), MINUTE(FunctionName.of("minute")), + MONTH(FunctionName.of("month")), + MONTHNAME(FunctionName.of("monthname")), + QUARTER(FunctionName.of("quarter")), SECOND(FunctionName.of("second")), - MICROSECOND(FunctionName.of("microsecond")), + SUBDATE(FunctionName.of("subdate")), TIME(FunctionName.of("time")), + TIME_TO_SEC(FunctionName.of("time_to_sec")), TIMESTAMP(FunctionName.of("timestamp")), - DAY(FunctionName.of("day")), - MONTH(FunctionName.of("month")), - QUARTER(FunctionName.of("quarter")), YEAR(FunctionName.of("year")), - TIME_TO_SEC(FunctionName.of("time_to_sec")), /** * Text Functions. diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 12fdd8579c..095e48e379 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -25,6 +25,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTERVAL; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.LONG; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.STRING; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; @@ -50,6 +51,7 @@ @ExtendWith(MockitoExtension.class) class DateTimeFunctionTest extends ExpressionTestBase { + @Mock Environment env; @@ -323,6 +325,98 @@ public void date() { assertEquals("date(DATE '2020-08-17')", expr.toString()); } + @Test + public void date_sub() { + FunctionExpression expr = dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); + assertEquals("date_sub(date(\"2020-08-26\"), 7)", expr.toString()); + + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); + assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), + dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 11:05:00"), expr.valueOf(env)); + assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", + expr.toString()); + + when(nullRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.date_sub(nullRef, DSL.literal(1L)))); + assertEquals(nullValue(), + eval(dsl.date_sub(nullRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(missingRef.type()).thenReturn(DATE); + assertEquals(missingValue(), eval(dsl.date_sub(missingRef, DSL.literal(1L)))); + assertEquals(missingValue(), + eval(dsl.date_sub(missingRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(nullRef.type()).thenReturn(LONG); + when(missingRef.type()).thenReturn(LONG); + assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(INTERVAL); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(missingValue(), eval(dsl.date_sub(nullRef, missingRef))); + } + + @Test + public void subdate() { + FunctionExpression expr = dsl.subdate(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); + assertEquals("subdate(date(\"2020-08-26\"), 7)", expr.toString()); + + expr = dsl.subdate(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); + assertEquals("subdate(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + + expr = dsl.subdate(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), + dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 11:05:00"), expr.valueOf(env)); + assertEquals("subdate(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", + expr.toString()); + + when(nullRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.subdate(nullRef, DSL.literal(1L)))); + assertEquals(nullValue(), + eval(dsl.subdate(nullRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(missingRef.type()).thenReturn(DATE); + assertEquals(missingValue(), eval(dsl.subdate(missingRef, DSL.literal(1L)))); + assertEquals(missingValue(), + eval(dsl.subdate(missingRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(nullRef.type()).thenReturn(LONG); + when(missingRef.type()).thenReturn(LONG); + assertEquals(nullValue(), eval(dsl.subdate(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.subdate(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(INTERVAL); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(nullValue(), eval(dsl.subdate(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.subdate(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(missingValue(), eval(dsl.subdate(nullRef, missingRef))); + } + @Test public void time() { when(nullRef.type()).thenReturn(TIME); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index b2f77aff02..325fe31f48 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -7,7 +7,7 @@ SQL Functions .. contents:: :local: - :depth: 1 + :depth: 2 Introduction ============ @@ -323,6 +323,30 @@ Specifications: 1. DATE_FORMAT(DATE, STRING) -> STRING 2. DATE_FORMAT(DATE, STRING, STRING) -> STRING +DATE_SUB +===== + +Description +----------- + +Usage: date_sub(date, INTERVAL expr unit) subtracts the time interval expr from date + +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL + +Return type: (DATE, DATE INTERVAL) -> DATE (DATE, TIME INTERVAL) -> DATETIME (DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + +Synonyms: SUBDATE + +Example:: + + od> SELECT DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), DATE_SUB(DATE('2020-08-26'), 1) + fetched rows / total rows = 1/1 + +------------------------------------------------+----------------------------------+ + | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2008-01-02'), 1) | + |------------------------------------------------+----------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | + +------------------------------------------------+----------------------------------+ + DAY ===== @@ -1157,6 +1181,30 @@ Example:: +-----------+--------------+ +SUBDATE +===== + +Description +----------- + +Usage: subdate(date,INTERVAL expr unit) subtracts time interval from date. subdate(expr, days) subtracts interval in day unit from the temporal expression expr. + +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL + +Return type: (DATE, DATE INTERVAL) -> DATE (DATE, TIME INTERVAL) -> DATETIME (DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + +Synonyms: DATE_SUB + +Example:: + + od> SELECT SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), SUBDATE(DATE('2020-08-26'), 1) + fetched rows / total rows = 1/1 + +-----------------------------------------------+---------------------------------+ + | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2008-01-02'), 1) | + |-----------------------------------------------+---------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | + +-----------------------------------------------+---------------------------------+ + SUBSTRING ========= @@ -1216,10 +1264,10 @@ Return type: LONG Example:: - od> SELECT time_to_sec(TIME '22:23:00') + od> SELECT TIME_TO_SEC(TIME '22:23:00') fetched rows / total rows = 1/1 +--------------------------------+ - | time_to_sec(TIME '22:23:00') | + | TIME_TO_SEC(TIME '22:23:00') | |--------------------------------| | 80580 | +--------------------------------+ diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index bf5abb502c..8bb7d7d3fb 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -196,14 +196,16 @@ TAN: 'TAN'; // DATE AND TIME FUNCTIONS DATE: 'DATE'; -TIME: 'TIME'; -TIMESTAMP: 'TIMESTAMP'; +DATE_SUB: 'DATE_SUB'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; MONTHNAME: 'MONTHNAME'; +SUBDATE: 'SUBDATE'; +TIME: 'TIME'; TIME_TO_SEC: 'TIME_TO_SEC'; +TIMESTAMP: 'TIMESTAMP'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 94443add6b..2944aec88d 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,9 +226,8 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND - | TIME_TO_SEC + : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND + | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 9c260d58d1..ce53921c37 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -173,11 +173,11 @@ CRC32: 'CRC32'; CURDATE: 'CURDATE'; DATE: 'DATE'; DATE_FORMAT: 'DATE_FORMAT'; +DATE_SUB: 'DATE_SUB'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; -TIME_TO_SEC: 'TIME_TO_SEC'; DEGREES: 'DEGREES'; E: 'E'; EXP: 'EXP'; @@ -213,9 +213,11 @@ SIGNUM: 'SIGNUM'; SIN: 'SIN'; SINH: 'SINH'; SQRT: 'SQRT'; +SUBDATE: 'SUBDATE'; SUBTRACT: 'SUBTRACT'; TAN: 'TAN'; TIME: 'TIME'; +TIME_TO_SEC: 'TIME_TO_SEC'; TIMESTAMP: 'TIMESTAMP'; TRUNCATE: 'TRUNCATE'; UPPER: 'UPPER'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index 2bef072989..f646ab4919 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -211,9 +211,8 @@ trigonometricFunctionName ; dateTimeFunctionName - : DAYNAME | MONTHNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | DATE - | TIME | TIMESTAMP | DAY | MONTH | QUARTER | YEAR | HOUR | MINUTE | SECOND | MICROSECOND - | TIME_TO_SEC + : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND + | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | YEAR ; functionArgs From 693211ad977bdd982bc2720b6c7cad212673099b Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 15 Sep 2020 13:28:00 -0700 Subject: [PATCH 23/42] fix doctest error --- docs/user/dql/functions.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 325fe31f48..bda0995de6 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -341,11 +341,11 @@ Example:: od> SELECT DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), DATE_SUB(DATE('2020-08-26'), 1) fetched rows / total rows = 1/1 - +------------------------------------------------+----------------------------------+ - | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2008-01-02'), 1) | - |------------------------------------------------+----------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | - +------------------------------------------------+----------------------------------+ + +-------------------------------------------------+-----------------------------------+ + | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | + |-------------------------------------------------+-----------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | + +-------------------------------------------------+-----------------------------------+ DAY ===== @@ -1199,11 +1199,11 @@ Example:: od> SELECT SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), SUBDATE(DATE('2020-08-26'), 1) fetched rows / total rows = 1/1 - +-----------------------------------------------+---------------------------------+ - | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2008-01-02'), 1) | - |-----------------------------------------------+---------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | - +-----------------------------------------------+---------------------------------+ + +------------------------------------------------+----------------------------------+ + | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | + |------------------------------------------------+----------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | + +------------------------------------------------+----------------------------------+ SUBSTRING ========= From 36449f7516f6cee16af96d4cd5959b2939d45420 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 15 Sep 2020 14:11:13 -0700 Subject: [PATCH 24/42] fix build error --- .../sql/expression/datetime/DateTimeFunctionTest.java | 4 +++- docs/user/dql/functions.rst | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 99ada39c10..ccf4cc990f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -23,6 +23,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.nullValue; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.stringValue; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; +import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTERVAL; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.LONG; @@ -33,6 +34,7 @@ import static org.mockito.Mockito.when; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDatetimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; @@ -103,7 +105,7 @@ public void dayOfMonth() { assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); - FunctionExpression expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-07-08"))); + expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-07-08"))); assertEquals(INTEGER, expression.type()); assertEquals("dayofmonth(DATE '2020-07-08')", expression.toString()); assertEquals(integerValue(8), eval(expression)); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index bda0995de6..eb19948231 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -7,7 +7,7 @@ SQL Functions .. contents:: :local: - :depth: 2 + :depth: 1 Introduction ============ From 048d5d6c976f7a34e22dd258173e9d77e2ac30ce Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 15 Sep 2020 16:54:08 -0700 Subject: [PATCH 25/42] add KeywordsCanBeId for dayofweek --- sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 index 131722c4e4..08de37fb7b 100644 --- a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 @@ -50,4 +50,9 @@ ident : DOT? ID | DOUBLE_QUOTE_ID | BACKTICK_QUOTE_ID + | keywordsCanBeId ; + +keywordsCanBeId + : DAYOFWEEK + ; \ No newline at end of file From c0593d9edc34038f93fd467e636b4c5c491049f3 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 16 Sep 2020 12:34:37 -0700 Subject: [PATCH 26/42] add to_days --- .../sql/expression/DSL.java | 4 ++++ .../expression/datetime/DateTimeFunction.java | 21 ++++++++++++++++- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 18 +++++++++++++++ docs/user/dql/functions.rst | 23 +++++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 3 ++- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 3 ++- 9 files changed, 72 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 903d14f3df..99ef3003f3 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -317,6 +317,10 @@ public FunctionExpression timestamp(Expression... expressions) { return function(BuiltinFunctionName.TIMESTAMP, expressions); } + public FunctionExpression to_days(Expression... expressions) { + return function(BuiltinFunctionName.TO_DAYS, expressions); + } + public FunctionExpression year(Expression... expressions) { return function(BuiltinFunctionName.YEAR, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 46a90c1cbc..fae2b59c96 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -17,7 +17,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression.datetime; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.getStringValue; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATE; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DATETIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER; @@ -77,6 +76,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(time()); repository.register(time_to_sec()); repository.register(timestamp()); + repository.register(to_days()); repository.register(year()); } @@ -316,6 +316,15 @@ private FunctionResolver timestamp() { impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIMESTAMP)); } + /** + * TO_DAYS(DATE). return the day number of the given date. + */ + private FunctionResolver to_days() { + return define(BuiltinFunctionName.TO_DAYS.getName(), + impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATE), + impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATETIME)); + } + /** * Date implementation for ExprValue. * @param exprValue ExprValue of Date type or String type. @@ -501,6 +510,16 @@ private ExprValue exprTimestamp(ExprValue exprValue) { } } + /** + * To_days implementation for ExprValue. + * @param exprValue ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprToDays(ExprValue exprValue) { + long days0000To1970 = (146097 * 5L) - (30L * 365L + 7L); + return new ExprLongValue(exprValue.dateValue().toEpochDay() + days0000To1970); + } + /** * Time To Sec implementation for ExprValue. * @param exprValue ExprValue of Time type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 592c53f719..f997aa7054 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -69,6 +69,7 @@ public enum BuiltinFunctionName { TIME(FunctionName.of("time")), TIME_TO_SEC(FunctionName.of("time_to_sec")), TIMESTAMP(FunctionName.of("timestamp")), + TO_DAYS(FunctionName.of("to_days")), YEAR(FunctionName.of("year")), /** diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index ccf4cc990f..0ac2ca43e1 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -463,6 +463,24 @@ public void timestamp() { assertEquals("timestamp(TIMESTAMP '2020-08-17 01:01:01')", expr.toString()); } + @Test + public void to_days() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.to_days(nullRef))); + assertEquals(missingValue(), eval(dsl.to_days(missingRef))); + + FunctionExpression expression = dsl.to_days(DSL.literal(new ExprDateValue("2008-10-07"))); + assertEquals(LONG, expression.type()); + assertEquals("to_days(DATE '2008-10-07')", expression.toString()); + assertEquals(longValue(733687L), eval(expression)); + + expression = dsl.to_days(DSL.literal(new ExprDateValue("1969-12-31"))); + assertEquals(LONG, expression.type()); + assertEquals("to_days(DATE '1969-12-31')", expression.toString()); + assertEquals(longValue(719527L), eval(expression)); + } + private ExprValue eval(Expression expression) { return expression.valueOf(env); } diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index eb19948231..d619382094 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1284,6 +1284,29 @@ Specifications: 1. TIMESTAMP(DATE) -> DATE +TO_DAYS +=== + +Description +----------- + +Usage: to_days(date) returns the day number (the number of days since year 0) of the given date. Returns NULL if date is invalid. + +Argument type: DATE + +Return type: LONG + +Example:: + + od> SELECT TO_DAYS(DATE '2008-10-07') + fetched rows / total rows = 1/1 + +------------------------------+ + | TO_DAYS(DATE '2008-10-07') | + |------------------------------| + | 733687 | + +------------------------------+ + + TRIM ==== diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index 8bb7d7d3fb..4e34c35773 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -206,6 +206,7 @@ SUBDATE: 'SUBDATE'; TIME: 'TIME'; TIME_TO_SEC: 'TIME_TO_SEC'; TIMESTAMP: 'TIMESTAMP'; +TO_DAYS: 'TO_DAYS'; // LITERALS AND VALUES //STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 2944aec88d..e884a52674 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -227,7 +227,8 @@ trigonometricFunctionName dateAndTimeFunctionBase : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND - | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | YEAR + | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP + | TO_DAYS | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index ce53921c37..81d0967c85 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -220,6 +220,7 @@ TIME: 'TIME'; TIME_TO_SEC: 'TIME_TO_SEC'; TIMESTAMP: 'TIMESTAMP'; TRUNCATE: 'TRUNCATE'; +TO_DAYS: 'TO_DAYS'; UPPER: 'UPPER'; D: 'D'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index 512c2a5450..d90f7517fe 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -231,7 +231,8 @@ trigonometricFunctionName dateTimeFunctionName : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND - | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | YEAR + | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP + | TO_DAYS | YEAR ; functionArgs From 7ee0dbc947f83b310ed1b5263f1ab3882d688225 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 16 Sep 2020 14:06:09 -0700 Subject: [PATCH 27/42] add from_days() --- .../sql/expression/DSL.java | 4 +++ .../expression/datetime/DateTimeFunction.java | 25 +++++++++++++++++-- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 14 +++++++++++ docs/user/dql/functions.rst | 23 +++++++++++++++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 6 ++--- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 6 ++--- 9 files changed, 73 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 99ef3003f3..30100e0a0d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -273,6 +273,10 @@ public FunctionExpression dayofyear(Expression... expressions) { return function(BuiltinFunctionName.DAYOFYEAR, expressions); } + public FunctionExpression from_days(Expression... expressions) { + return function(BuiltinFunctionName.FROM_DAYS, expressions); + } + public FunctionExpression hour(Expression... expressions) { return function(BuiltinFunctionName.HOUR, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index fae2b59c96..4b7d399351 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -41,6 +41,7 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import com.google.common.base.CharMatcher; +import java.time.LocalDate; import java.time.format.TextStyle; import java.util.Locale; import lombok.experimental.UtilityClass; @@ -52,6 +53,10 @@ */ @UtilityClass public class DateTimeFunction { + + // The number of days from year zero to year 1970. + private static final Long DAYS_0000_TO_1970 = (146097 * 5L) - (30L * 365L + 7L); + /** * Register Date and Time Functions. * @@ -65,6 +70,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(dayOfMonth()); repository.register(dayOfWeek()); repository.register(dayOfYear()); + repository.register(from_days()); repository.register(hour()); repository.register(microsecond()); repository.register(minute()); @@ -193,6 +199,14 @@ private FunctionResolver day() { ); } + /** + * FROM_DAYS(DATE). return the date value given the day number N. + */ + private FunctionResolver from_days() { + return define(BuiltinFunctionName.FROM_DAYS.getName(), + impl(nullMissingHandling(DateTimeFunction::exprFromDays), DATE, LONG)); + } + /** * HOUR(TIME). return the hour value for time. */ @@ -446,6 +460,14 @@ private ExprValue exprDayOfYear(ExprValue date) { return new ExprIntegerValue(date.dateValue().getDayOfYear()); } + /** From_days implementation for ExprValue. + * @param exprValue Day number N. + * @return ExprValue. + */ + private ExprValue exprFromDays(ExprValue exprValue) { + return new ExprDateValue(LocalDate.ofEpochDay(exprValue.longValue() - DAYS_0000_TO_1970)); + } + /** * Hour implementation for ExprValue. * @param exprValue ExprValue of Time type. @@ -516,8 +538,7 @@ private ExprValue exprTimestamp(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprToDays(ExprValue exprValue) { - long days0000To1970 = (146097 * 5L) - (30L * 365L + 7L); - return new ExprLongValue(exprValue.dateValue().toEpochDay() + days0000To1970); + return new ExprLongValue(exprValue.dateValue().toEpochDay() + DAYS_0000_TO_1970); } /** diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index f997aa7054..1a2fa819c7 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -58,6 +58,7 @@ public enum BuiltinFunctionName { DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), + FROM_DAYS(FunctionName.of("from_days")), HOUR(FunctionName.of("hour")), MICROSECOND(FunctionName.of("microsecond")), MINUTE(FunctionName.of("minute")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 0ac2ca43e1..9188809489 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -35,6 +35,7 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDatetimeValue; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprLongValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; @@ -161,6 +162,19 @@ public void day() { assertEquals(missingValue(), eval(dsl.day(missingRef))); } + @Test + public void from_days() { + when(nullRef.type()).thenReturn(LONG); + when(missingRef.type()).thenReturn(LONG); + assertEquals(nullValue(), eval(dsl.from_days(nullRef))); + assertEquals(missingValue(), eval(dsl.from_days(missingRef))); + + FunctionExpression expression = dsl.from_days(DSL.literal(new ExprLongValue(730669))); + assertEquals(DATE, expression.type()); + assertEquals("from_days(730669)", expression.toString()); + assertEquals(new ExprDateValue("2000-07-03"), expression.valueOf(env)); + } + @Test public void hour() { when(nullRef.type()).thenReturn(TIME); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index d619382094..fb9a275c17 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -552,6 +552,29 @@ Specifications: 1. FLOOR(NUMBER T) -> T +FROM_DAYS +=== + +Description +----------- + +Usage: from_days(N) returns the date value given the day number N. + +Argument type: INTEGER/LONG + +Return type: DATE + +Example:: + + od> SELECT FROM_DAYS(733687) + fetched rows / total rows = 1/1 + +---------------------+ + | FROM_DAYS(733687) | + |---------------------| + | 2008-10-07 | + +---------------------+ + + HOUR ===== diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index 4e34c35773..e50d493f5c 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -201,6 +201,7 @@ DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; DAYOFYEAR: 'DAYOFYEAR'; DAYNAME: 'DAYNAME'; +FROM_DAYS: 'FROM_DAYS'; MONTHNAME: 'MONTHNAME'; SUBDATE: 'SUBDATE'; TIME: 'TIME'; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index e884a52674..9a961c1bf3 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,9 +226,9 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND - | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP - | TO_DAYS | YEAR + : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR + | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC + | TIMESTAMP | TO_DAYS | YEAR ; textFunctionBase diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 81d0967c85..66dab3414d 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -183,6 +183,7 @@ E: 'E'; EXP: 'EXP'; EXPM1: 'EXPM1'; FLOOR: 'FLOOR'; +FROM_DAYS: 'FROM_DAYS'; IF: 'IF'; IFNULL: 'IFNULL'; ISNULL: 'ISNULL'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index d90f7517fe..e6d4eb87b3 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -230,9 +230,9 @@ trigonometricFunctionName ; dateTimeFunctionName - : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | HOUR | MICROSECOND - | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP - | TO_DAYS | YEAR + : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR + | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC + | TIMESTAMP | TO_DAYS | YEAR ; functionArgs From 7764a0d4d3e2cf1e6c03d7669609bbe8ca422d19 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 17 Sep 2020 11:12:57 -0700 Subject: [PATCH 28/42] arrange by alphabetical order --- .../expression/datetime/DateTimeFunction.java | 294 ++++++++--------- .../datetime/DateTimeFunctionTest.java | 308 +++++++++--------- 2 files changed, 301 insertions(+), 301 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 4b7d399351..ccad83c731 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -119,21 +119,12 @@ private FunctionResolver date_sub() { } /** - * Extracts the date part of a date and time value. - * Also to construct a date type. The supported signatures: - * STRING/DATE/DATETIME/TIMESTAMP -> DATE + * DAY(DATE). return the day of the month (1-31). */ - private FunctionResolver subdate() { - return define(BuiltinFunctionName.SUBDATE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), - DATETIME, DATETIME, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), - DATETIME, TIMESTAMP, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) + private FunctionResolver day() { + return define(BuiltinFunctionName.DAY.getName(), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), + INTEGER, DATE) ); } @@ -148,16 +139,6 @@ private FunctionResolver dayName() { ); } - /** - * MONTHNAME(DATE). return the full name of the month for date. - */ - private FunctionResolver monthName() { - return define(BuiltinFunctionName.MONTHNAME.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMonthName), - STRING, DATE) - ); - } - /** * DAYOFMONTH(DATE). return the day of the month (1-31). */ @@ -189,16 +170,6 @@ private FunctionResolver dayOfYear() { ); } - /** - * DAY(DATE). return the day of the month (1-31). - */ - private FunctionResolver day() { - return define(BuiltinFunctionName.DAY.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), - INTEGER, DATE) - ); - } - /** * FROM_DAYS(DATE). return the date value given the day number N. */ @@ -222,43 +193,29 @@ private FunctionResolver hour() { } /** - * MINUTE(TIME). return the minute value for time. - */ - private FunctionResolver minute() { - return define(BuiltinFunctionName.MINUTE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, TIMESTAMP) - ); - } - - /** - * SECOND(TIME). return the second value for time. + * MICROSECOND(TIME). return the microsecond value for time. */ - private FunctionResolver second() { - return define(BuiltinFunctionName.SECOND.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSecond), + private FunctionResolver microsecond() { + return define(BuiltinFunctionName.MICROSECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSecond), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSecond), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIMESTAMP) ); } /** - * MICROSECOND(TIME). return the microsecond value for time. + * MINUTE(TIME). return the minute value for time. */ - private FunctionResolver microsecond() { - return define(BuiltinFunctionName.MICROSECOND.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + private FunctionResolver minute() { + return define(BuiltinFunctionName.MINUTE.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIMESTAMP) ); } @@ -273,6 +230,16 @@ private FunctionResolver month() { ); } + /** + * MONTHNAME(DATE). return the full name of the month for date. + */ + private FunctionResolver monthName() { + return define(BuiltinFunctionName.MONTHNAME.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMonthName), + STRING, DATE) + ); + } + /** * QUARTER(DATE). return the month for date (1-4). */ @@ -284,22 +251,35 @@ private FunctionResolver quarter() { } /** - * YEAR(DATE). return the year for date (1000-9999). + * SECOND(TIME). return the second value for time. */ - private FunctionResolver year() { - return define(BuiltinFunctionName.YEAR.getName(), - impl(nullMissingHandling(DateTimeFunction::exprYear), - INTEGER, DATE) + private FunctionResolver second() { + return define(BuiltinFunctionName.SECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), + INTEGER, TIMESTAMP) ); } /** - * TIME_TO_SEC(TIME). return the time argument, converted to seconds. + * Extracts the date part of a date and time value. + * Also to construct a date type. The supported signatures: + * STRING/DATE/DATETIME/TIMESTAMP -> DATE */ - private FunctionResolver time_to_sec() { - return define(BuiltinFunctionName.TIME_TO_SEC.getName(), - impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), - LONG, TIME) + private FunctionResolver subdate() { + return define(BuiltinFunctionName.SUBDATE.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, DATETIME, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, TIMESTAMP, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) ); } @@ -317,6 +297,16 @@ private FunctionResolver time() { impl(nullMissingHandling(DateTimeFunction::exprTime), TIME, TIMESTAMP)); } + /** + * TIME_TO_SEC(TIME). return the time argument, converted to seconds. + */ + private FunctionResolver time_to_sec() { + return define(BuiltinFunctionName.TIME_TO_SEC.getName(), + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), + LONG, TIME) + ); + } + /** * Extracts the timestamp of a date and time value. * Also to construct a date type. The supported signatures: @@ -339,6 +329,16 @@ private FunctionResolver to_days() { impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATETIME)); } + /** + * YEAR(DATE). return the year for date (1000-9999). + */ + private FunctionResolver year() { + return define(BuiltinFunctionName.YEAR.getName(), + impl(nullMissingHandling(DateTimeFunction::exprYear), + INTEGER, DATE) + ); + } + /** * Date implementation for ExprValue. * @param exprValue ExprValue of Date type or String type. @@ -352,62 +352,6 @@ private ExprValue exprDate(ExprValue exprValue) { } } - /** - * SUBDATE function implementation for ExprValue. - * - * @param date ExprValue of Date/Datetime/Timestamp type. - * @param expr ExprValue of Interval type, the temporal amount to subtract. - * @return Date/Datetime resulted from expr subtracted to date. - */ - private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { - return new ExprDatetimeValue(date.datetimeValue().minus(expr.intervalValue())); - } - - /** - * SUBDATE function implementation for ExprValue. - * - * @param date ExprValue of Date/Datetime/Timestamp type. - * @param days ExprValue of Long type, representing the number of days to subtract. - * @return Date/Datetime resulted from days subtracted to date. - */ - private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { - if (date instanceof ExprDateValue) { - return new ExprDateValue(date.dateValue().minusDays(days.longValue())); - } else { - return new ExprDatetimeValue(date.datetimeValue().minusDays(days.longValue())); - } - } - - /** - * Month for date implementation for ExprValue. - * @param date ExprValue of Date type. - * @return ExprValue. - */ - private ExprValue exprMonth(ExprValue date) { - return new ExprIntegerValue(date.dateValue().getMonthValue()); - } - - /** - * Quarter for date implementation for ExprValue. - * - * @param date ExprValue of Date type. - * @return ExprValue. - */ - private ExprValue exprQuarter(ExprValue date) { - return new ExprIntegerValue((date.dateValue().getMonthValue() % 3) == 0 - ? (date.dateValue().getMonthValue() / 3) - : ((date.dateValue().getMonthValue() / 3) + 1)); - } - - /** - * Year for date implementation for ExprValue. - * @param date ExprValue of Date type. - * @return ExprValue. - */ - private ExprValue exprYear(ExprValue date) { - return new ExprIntegerValue(date.dateValue().getYear()); - } - /** * Name of the Weekday implementation for ExprValue. * @param date ExprValue of Date type. @@ -418,16 +362,6 @@ private ExprValue exprDayName(ExprValue date) { date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); } - /** - * Name of the Month implementation for ExprValue. - * @param date ExprValue of Date type. - * @return ExprValue. - */ - private ExprValue exprMonthName(ExprValue date) { - return new ExprStringValue( - date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); - } - /** * Day of Month implementation for ExprValue. * @param date ExprValue of Date type. @@ -477,6 +411,17 @@ private ExprValue exprHour(ExprValue exprValue) { return new ExprIntegerValue(exprValue.timeValue().getHour()); } + /** + * Microsecond implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprMicrosecond(ExprValue exprValue) { + return new ExprIntegerValue((exprValue.timeValue().getNano() == 0) ? 0 + : Integer.parseInt(CharMatcher.is('0') + .trimTrailingFrom(Integer.toString(exprValue.timeValue().getNano())))); + } + /** * Minute implementation for ExprValue. * @param exprValue ExprValue of Time type. @@ -486,6 +431,37 @@ private ExprValue exprMinute(ExprValue exprValue) { return new ExprIntegerValue(exprValue.timeValue().getMinute()); } + /** + * Month for date implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprMonth(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getMonthValue()); + } + + /** + * Name of the Month implementation for ExprValue. + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprMonthName(ExprValue date) { + return new ExprStringValue( + date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); + } + + /** + * Quarter for date implementation for ExprValue. + * + * @param date ExprValue of Date type. + * @return ExprValue. + */ + private ExprValue exprQuarter(ExprValue date) { + return new ExprIntegerValue((date.dateValue().getMonthValue() % 3) == 0 + ? (date.dateValue().getMonthValue() / 3) + : ((date.dateValue().getMonthValue() / 3) + 1)); + } + /** * Second implementation for ExprValue. * @param exprValue ExprValue of Time type. @@ -496,14 +472,29 @@ private ExprValue exprSecond(ExprValue exprValue) { } /** - * Microsecond implementation for ExprValue. - * @param exprValue ExprValue of Time type. - * @return ExprValue. + * SUBDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param days ExprValue of Long type, representing the number of days to subtract. + * @return Date/Datetime resulted from days subtracted to date. */ - private ExprValue exprMicrosecond(ExprValue exprValue) { - return new ExprIntegerValue((exprValue.timeValue().getNano() == 0) ? 0 - : Integer.parseInt(CharMatcher.is('0') - .trimTrailingFrom(Integer.toString(exprValue.timeValue().getNano())))); + private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { + if (date instanceof ExprDateValue) { + return new ExprDateValue(date.dateValue().minusDays(days.longValue())); + } else { + return new ExprDatetimeValue(date.datetimeValue().minusDays(days.longValue())); + } + } + + /** + * SUBDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param expr ExprValue of Interval type, the temporal amount to subtract. + * @return Date/Datetime resulted from expr subtracted to date. + */ + private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { + return new ExprDatetimeValue(date.datetimeValue().minus(expr.intervalValue())); } /** @@ -532,6 +523,15 @@ private ExprValue exprTimestamp(ExprValue exprValue) { } } + /** + * Time To Sec implementation for ExprValue. + * @param exprValue ExprValue of Time type. + * @return ExprValue. + */ + private ExprValue exprTimeToSec(ExprValue exprValue) { + return new ExprLongValue(exprValue.timeValue().toSecondOfDay()); + } + /** * To_days implementation for ExprValue. * @param exprValue ExprValue of Date type. @@ -542,11 +542,11 @@ private ExprValue exprToDays(ExprValue exprValue) { } /** - * Time To Sec implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * Year for date implementation for ExprValue. + * @param date ExprValue of Date type. * @return ExprValue. */ - private ExprValue exprTimeToSec(ExprValue exprValue) { - return new ExprLongValue(exprValue.timeValue().toSecondOfDay()); + private ExprValue exprYear(ExprValue date) { + return new ExprIntegerValue(date.dateValue().getYear()); } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 9188809489..9d1f9a2def 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -69,29 +69,93 @@ public void setup() { } @Test - public void dayName() { + public void date() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.date(nullRef))); + assertEquals(missingValue(), eval(dsl.date(missingRef))); - FunctionExpression expression = dsl.dayname(DSL.literal(new ExprDateValue("2020-08-07"))); - assertEquals(STRING, expression.type()); - assertEquals("dayname(DATE '2020-08-07')", expression.toString()); - assertEquals(stringValue("Friday"), eval(expression)); - assertEquals(nullValue(), eval(dsl.dayname(nullRef))); - assertEquals(missingValue(), eval(dsl.dayname(missingRef))); + FunctionExpression expr = dsl.date(DSL.literal("2020-08-17")); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-08-17"), eval(expr)); + assertEquals("date(\"2020-08-17\")", expr.toString()); + + expr = dsl.date(DSL.literal(new ExprDateValue("2020-08-17"))); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-08-17"), eval(expr)); + assertEquals("date(DATE '2020-08-17')", expr.toString()); } @Test - public void monthName() { + public void date_sub() { + FunctionExpression expr = dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); + assertEquals("date_sub(date(\"2020-08-26\"), 7)", expr.toString()); + + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); + assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), + dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 11:05:00"), expr.valueOf(env)); + assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", + expr.toString()); + when(nullRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.date_sub(nullRef, DSL.literal(1L)))); + assertEquals(nullValue(), + eval(dsl.date_sub(nullRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + when(missingRef.type()).thenReturn(DATE); + assertEquals(missingValue(), eval(dsl.date_sub(missingRef, DSL.literal(1L)))); + assertEquals(missingValue(), + eval(dsl.date_sub(missingRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); - FunctionExpression expression = dsl.monthname(DSL.literal(new ExprDateValue("2020-08-07"))); + when(nullRef.type()).thenReturn(LONG); + when(missingRef.type()).thenReturn(LONG); + assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(INTERVAL); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(missingValue(), eval(dsl.date_sub(nullRef, missingRef))); + } + + @Test + public void day() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.day(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("day(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(7), eval(expression)); + assertEquals(nullValue(), eval(dsl.day(nullRef))); + assertEquals(missingValue(), eval(dsl.day(missingRef))); + } + + @Test + public void dayName() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.dayname(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(STRING, expression.type()); - assertEquals("monthname(DATE '2020-08-07')", expression.toString()); - assertEquals(stringValue("August"), eval(expression)); - assertEquals(nullValue(), eval(dsl.monthname(nullRef))); - assertEquals(missingValue(), eval(dsl.monthname(missingRef))); + assertEquals("dayname(DATE '2020-08-07')", expression.toString()); + assertEquals(stringValue("Friday"), eval(expression)); + assertEquals(nullValue(), eval(dsl.dayname(nullRef))); + assertEquals(missingValue(), eval(dsl.dayname(missingRef))); } @Test @@ -149,19 +213,6 @@ public void dayOfYear() { assertEquals(missingValue(), eval(dsl.dayofyear(missingRef))); } - @Test - public void day() { - when(nullRef.type()).thenReturn(DATE); - when(missingRef.type()).thenReturn(DATE); - - FunctionExpression expression = dsl.day(DSL.literal(new ExprDateValue("2020-08-07"))); - assertEquals(INTEGER, expression.type()); - assertEquals("day(DATE '2020-08-07')", expression.toString()); - assertEquals(integerValue(7), eval(expression)); - assertEquals(nullValue(), eval(dsl.day(nullRef))); - assertEquals(missingValue(), eval(dsl.day(missingRef))); - } - @Test public void from_days() { when(nullRef.type()).thenReturn(LONG); @@ -198,52 +249,6 @@ public void hour() { assertEquals("hour(DATETIME '2020-08-17 01:02:03')", expression.toString()); } - @Test - public void minute() { - when(nullRef.type()).thenReturn(TIME); - when(missingRef.type()).thenReturn(TIME); - assertEquals(nullValue(), eval(dsl.minute(nullRef))); - assertEquals(missingValue(), eval(dsl.minute(missingRef))); - - FunctionExpression expression = dsl.minute(DSL.literal(new ExprTimeValue("01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(2), eval(expression)); - assertEquals("minute(TIME '01:02:03')", expression.toString()); - - expression = dsl.minute(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(2), expression.valueOf(env)); - assertEquals("minute(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); - - expression = dsl.minute(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(2), expression.valueOf(env)); - assertEquals("minute(DATETIME '2020-08-17 01:02:03')", expression.toString()); - } - - @Test - public void second() { - when(nullRef.type()).thenReturn(TIME); - when(missingRef.type()).thenReturn(TIME); - assertEquals(nullValue(), eval(dsl.second(nullRef))); - assertEquals(missingValue(), eval(dsl.second(missingRef))); - - FunctionExpression expression = dsl.second(DSL.literal(new ExprTimeValue("01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(3), eval(expression)); - assertEquals("second(TIME '01:02:03')", expression.toString()); - - expression = dsl.second(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(3), expression.valueOf(env)); - assertEquals("second(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); - - expression = dsl.second(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); - assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(3), expression.valueOf(env)); - assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); - } - @Test public void microsecond() { when(nullRef.type()).thenReturn(TIME); @@ -273,6 +278,29 @@ public void microsecond() { assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString()); } + @Test + public void minute() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.minute(nullRef))); + assertEquals(missingValue(), eval(dsl.minute(missingRef))); + + FunctionExpression expression = dsl.minute(DSL.literal(new ExprTimeValue("01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), eval(expression)); + assertEquals("minute(TIME '01:02:03')", expression.toString()); + + expression = dsl.minute(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), expression.valueOf(env)); + assertEquals("minute(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.minute(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), expression.valueOf(env)); + assertEquals("minute(DATETIME '2020-08-17 01:02:03')", expression.toString()); + } + @Test public void month() { when(nullRef.type()).thenReturn(DATE); @@ -286,6 +314,19 @@ public void month() { assertEquals(missingValue(), eval(dsl.month(missingRef))); } + @Test + public void monthName() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.monthname(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(STRING, expression.type()); + assertEquals("monthname(DATE '2020-08-07')", expression.toString()); + assertEquals(stringValue("August"), eval(expression)); + assertEquals(nullValue(), eval(dsl.monthname(nullRef))); + assertEquals(missingValue(), eval(dsl.monthname(missingRef))); + } + @Test public void quarter() { when(nullRef.type()).thenReturn(DATE); @@ -306,93 +347,26 @@ public void quarter() { } @Test - public void year() { - when(nullRef.type()).thenReturn(DATE); - when(missingRef.type()).thenReturn(DATE); - - FunctionExpression expression = dsl.year(DSL.literal(new ExprDateValue("2020-08-07"))); - assertEquals(INTEGER, expression.type()); - assertEquals("year(DATE '2020-08-07')", expression.toString()); - assertEquals(integerValue(2020), eval(expression)); - assertEquals(nullValue(), eval(dsl.year(nullRef))); - assertEquals(missingValue(), eval(dsl.year(missingRef))); - } - - @Test - public void time_to_sec() { + public void second() { when(nullRef.type()).thenReturn(TIME); when(missingRef.type()).thenReturn(TIME); - assertEquals(nullValue(), eval(dsl.time_to_sec(nullRef))); - assertEquals(missingValue(), eval(dsl.time_to_sec(missingRef))); - - FunctionExpression expression = dsl.time_to_sec(DSL.literal(new ExprTimeValue("22:23:00"))); - assertEquals(LONG, expression.type()); - assertEquals("time_to_sec(TIME '22:23:00')", expression.toString()); - assertEquals(longValue(80580L), eval(expression)); - } - - @Test - public void date() { - when(nullRef.type()).thenReturn(DATE); - when(missingRef.type()).thenReturn(DATE); - assertEquals(nullValue(), eval(dsl.date(nullRef))); - assertEquals(missingValue(), eval(dsl.date(missingRef))); - - FunctionExpression expr = dsl.date(DSL.literal("2020-08-17")); - assertEquals(DATE, expr.type()); - assertEquals(new ExprDateValue("2020-08-17"), eval(expr)); - assertEquals("date(\"2020-08-17\")", expr.toString()); - - expr = dsl.date(DSL.literal(new ExprDateValue("2020-08-17"))); - assertEquals(DATE, expr.type()); - assertEquals(new ExprDateValue("2020-08-17"), eval(expr)); - assertEquals("date(DATE '2020-08-17')", expr.toString()); - } - - @Test - public void date_sub() { - FunctionExpression expr = dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); - assertEquals(DATE, expr.type()); - assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); - assertEquals("date_sub(date(\"2020-08-26\"), 7)", expr.toString()); - - expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); - assertEquals(DATETIME, expr.type()); - assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); - assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); - - expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), - dsl.interval(DSL.literal(1), DSL.literal("hour"))); - assertEquals(DATETIME, expr.type()); - assertEquals(new ExprDatetimeValue("2020-08-26 11:05:00"), expr.valueOf(env)); - assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", - expr.toString()); - - when(nullRef.type()).thenReturn(DATE); - assertEquals(nullValue(), eval(dsl.date_sub(nullRef, DSL.literal(1L)))); - assertEquals(nullValue(), - eval(dsl.date_sub(nullRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); - - when(missingRef.type()).thenReturn(DATE); - assertEquals(missingValue(), eval(dsl.date_sub(missingRef, DSL.literal(1L)))); - assertEquals(missingValue(), - eval(dsl.date_sub(missingRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + assertEquals(nullValue(), eval(dsl.second(nullRef))); + assertEquals(missingValue(), eval(dsl.second(missingRef))); - when(nullRef.type()).thenReturn(LONG); - when(missingRef.type()).thenReturn(LONG); - assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); - assertEquals(missingValue(), - eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + FunctionExpression expression = dsl.second(DSL.literal(new ExprTimeValue("01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), eval(expression)); + assertEquals("second(TIME '01:02:03')", expression.toString()); - when(nullRef.type()).thenReturn(INTERVAL); - when(missingRef.type()).thenReturn(INTERVAL); - assertEquals(nullValue(), eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), nullRef))); - assertEquals(missingValue(), - eval(dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), missingRef))); + expression = dsl.second(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), expression.valueOf(env)); + assertEquals("second(TIMESTAMP '2020-08-17 01:02:03')", expression.toString()); - when(nullRef.type()).thenReturn(DATE); - when(missingRef.type()).thenReturn(INTERVAL); - assertEquals(missingValue(), eval(dsl.date_sub(nullRef, missingRef))); + expression = dsl.second(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), expression.valueOf(env)); + assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); } @Test @@ -441,6 +415,19 @@ public void subdate() { assertEquals(missingValue(), eval(dsl.subdate(nullRef, missingRef))); } + @Test + public void time_to_sec() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + assertEquals(nullValue(), eval(dsl.time_to_sec(nullRef))); + assertEquals(missingValue(), eval(dsl.time_to_sec(missingRef))); + + FunctionExpression expression = dsl.time_to_sec(DSL.literal(new ExprTimeValue("22:23:00"))); + assertEquals(LONG, expression.type()); + assertEquals("time_to_sec(TIME '22:23:00')", expression.toString()); + assertEquals(longValue(80580L), eval(expression)); + } + @Test public void time() { when(nullRef.type()).thenReturn(TIME); @@ -495,6 +482,19 @@ public void to_days() { assertEquals(longValue(719527L), eval(expression)); } + @Test + public void year() { + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(DATE); + + FunctionExpression expression = dsl.year(DSL.literal(new ExprDateValue("2020-08-07"))); + assertEquals(INTEGER, expression.type()); + assertEquals("year(DATE '2020-08-07')", expression.toString()); + assertEquals(integerValue(2020), eval(expression)); + assertEquals(nullValue(), eval(dsl.year(nullRef))); + assertEquals(missingValue(), eval(dsl.year(missingRef))); + } + private ExprValue eval(Expression expression) { return expression.valueOf(env); } From 18a6a8489bcd50b0edfe847da96252f31caa7115 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 17 Sep 2020 14:51:56 -0700 Subject: [PATCH 29/42] add manual IT --- .../datetime/DateTimeFunctionTest.java | 43 ++-- .../sql/sql/DateTimeFunctionIT.java | 208 ++++++++++++++++++ 2 files changed, 226 insertions(+), 25 deletions(-) create mode 100644 integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 9d1f9a2def..2a9ca92e7f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -136,44 +136,39 @@ public void date_sub() { public void day() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.day(nullRef))); + assertEquals(missingValue(), eval(dsl.day(missingRef))); FunctionExpression expression = dsl.day(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); assertEquals("day(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(7), eval(expression)); - assertEquals(nullValue(), eval(dsl.day(nullRef))); - assertEquals(missingValue(), eval(dsl.day(missingRef))); } @Test public void dayName() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.dayname(nullRef))); + assertEquals(missingValue(), eval(dsl.dayname(missingRef))); FunctionExpression expression = dsl.dayname(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(STRING, expression.type()); assertEquals("dayname(DATE '2020-08-07')", expression.toString()); assertEquals(stringValue("Friday"), eval(expression)); - assertEquals(nullValue(), eval(dsl.dayname(nullRef))); - assertEquals(missingValue(), eval(dsl.dayname(missingRef))); } @Test public void dayOfMonth() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); FunctionExpression expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); assertEquals("dayofmonth(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(7), eval(expression)); - assertEquals(nullValue(), eval(dsl.dayofmonth(nullRef))); - assertEquals(missingValue(), eval(dsl.dayofmonth(missingRef))); - - expression = dsl.dayofmonth(DSL.literal(new ExprDateValue("2020-07-08"))); - assertEquals(INTEGER, expression.type()); - assertEquals("dayofmonth(DATE '2020-07-08')", expression.toString()); - assertEquals(integerValue(8), eval(expression)); expression = dsl.dayofmonth(DSL.literal("2020-07-08")); assertEquals(INTEGER, expression.type()); @@ -185,6 +180,8 @@ public void dayOfMonth() { public void dayOfWeek() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.dayofweek(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofweek(missingRef))); FunctionExpression expression = dsl.dayofweek(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); @@ -195,22 +192,19 @@ public void dayOfWeek() { assertEquals(INTEGER, expression.type()); assertEquals("dayofweek(DATE '2020-08-09')", expression.toString()); assertEquals(integerValue(1), eval(expression)); - - assertEquals(nullValue(), eval(dsl.dayofweek(nullRef))); - assertEquals(missingValue(), eval(dsl.dayofweek(missingRef))); } @Test public void dayOfYear() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.dayofyear(nullRef))); + assertEquals(missingValue(), eval(dsl.dayofyear(missingRef))); FunctionExpression expression = dsl.dayofyear(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); assertEquals("dayofyear(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(220), eval(expression)); - assertEquals(nullValue(), eval(dsl.dayofyear(nullRef))); - assertEquals(missingValue(), eval(dsl.dayofyear(missingRef))); } @Test @@ -305,32 +299,34 @@ public void minute() { public void month() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.month(nullRef))); + assertEquals(missingValue(), eval(dsl.month(missingRef))); FunctionExpression expression = dsl.month(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); assertEquals("month(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(8), eval(expression)); - assertEquals(nullValue(), eval(dsl.month(nullRef))); - assertEquals(missingValue(), eval(dsl.month(missingRef))); } @Test public void monthName() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.monthname(nullRef))); + assertEquals(missingValue(), eval(dsl.monthname(missingRef))); FunctionExpression expression = dsl.monthname(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(STRING, expression.type()); assertEquals("monthname(DATE '2020-08-07')", expression.toString()); assertEquals(stringValue("August"), eval(expression)); - assertEquals(nullValue(), eval(dsl.monthname(nullRef))); - assertEquals(missingValue(), eval(dsl.monthname(missingRef))); } @Test public void quarter() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.quarter(nullRef))); + assertEquals(missingValue(), eval(dsl.quarter(missingRef))); FunctionExpression expression = dsl.quarter(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); @@ -341,9 +337,6 @@ public void quarter() { assertEquals(INTEGER, expression.type()); assertEquals("quarter(DATE '2020-12-07')", expression.toString()); assertEquals(integerValue(4), eval(expression)); - - assertEquals(nullValue(), eval(dsl.quarter(nullRef))); - assertEquals(missingValue(), eval(dsl.quarter(missingRef))); } @Test @@ -486,13 +479,13 @@ public void to_days() { public void year() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.year(nullRef))); + assertEquals(missingValue(), eval(dsl.year(missingRef))); FunctionExpression expression = dsl.year(DSL.literal(new ExprDateValue("2020-08-07"))); assertEquals(INTEGER, expression.type()); assertEquals("year(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(2020), eval(expression)); - assertEquals(nullValue(), eval(dsl.year(nullRef))); - assertEquals(missingValue(), eval(dsl.year(missingRef))); } private ExprValue eval(Expression expression) { diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java new file mode 100644 index 0000000000..2b7481b01e --- /dev/null +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -0,0 +1,208 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.sql; + +import static com.amazon.opendistroforelasticsearch.sql.legacy.plugin.RestSqlAction.QUERY_API_ENDPOINT; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.rows; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.schema; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyDataRows; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifySchema; +import static com.amazon.opendistroforelasticsearch.sql.util.TestUtils.getResponseBody; + +import com.amazon.opendistroforelasticsearch.sql.legacy.SQLIntegTestCase; +import com.amazon.opendistroforelasticsearch.sql.util.TestUtils; +import java.io.IOException; +import java.util.Locale; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.Response; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + +public class DateTimeFunctionIT extends SQLIntegTestCase { + + @Override + public void init() throws Exception { + super.init(); + TestUtils.enableNewQueryEngine(client()); + } + + @Test + public void testDateSub() throws IOException { + JSONObject result = + executeQuery("select date_sub(timestamp('2020-09-16 17:30:00'), interval 1 day)"); + verifySchema(result, + schema("date_sub(timestamp('2020-09-16 17:30:00'), interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15 17:30:00")); + + result = executeQuery("select date_sub(date('2020-09-16'), 1)"); + verifySchema(result, schema("date_sub(date('2020-09-16'), 1)", null, "date")); + verifyDataRows(result, rows("2020-09-15")); + } + + @Test + public void testDay() throws IOException { + JSONObject result = executeQuery("select day(date('2020-09-16'))"); + verifySchema(result, schema("day(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(16)); + } + + @Test + public void testDayName() throws IOException { + JSONObject result = executeQuery("select dayname(date('2020-09-16'))"); + verifySchema(result, schema("dayname(date('2020-09-16'))", null, "string")); + verifyDataRows(result, rows("Wednesday")); + } + + @Test + public void testDayOfMonth() throws IOException { + JSONObject result = executeQuery("select dayofmonth(date('2020-09-16'))"); + verifySchema(result, schema("dayofmonth(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(16)); + } + + @Test + public void testDayOfWeek() throws IOException { + JSONObject result = executeQuery("select dayofweek(date('2020-09-16'))"); + verifySchema(result, schema("dayofweek(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(4)); + } + + @Test + public void testDayOfYear() throws IOException { + JSONObject result = executeQuery("select dayofyear(date('2020-09-16'))"); + verifySchema(result, schema("dayofyear(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(260)); + } + + @Test + public void testFromDays() throws IOException { + JSONObject result = executeQuery("select from_days(738049)"); + verifySchema(result, schema("from_days(738049)", null, "date")); + verifyDataRows(result, rows("2020-09-16")); + } + + @Test + public void testHour() throws IOException { + JSONObject result = executeQuery("select hour(timestamp('2020-09-16 17:30:00'))"); + verifySchema(result, schema("hour(timestamp('2020-09-16 17:30:00'))", null, "integer")); + verifyDataRows(result, rows(17)); + + result = executeQuery("select hour(time('17:30:00'))"); + verifySchema(result, schema("hour(time('17:30:00'))", null, "integer")); + verifyDataRows(result, rows(17)); + } + + @Test + public void testMicrosecond() throws IOException { + JSONObject result = executeQuery("select microsecond(timestamp('2020-09-16 17:30:00.123456'))"); + verifySchema(result, schema("microsecond(timestamp('2020-09-16 17:30:00.123456'))", null, "integer")); + verifyDataRows(result, rows(123456)); + + result = executeQuery("select microsecond(time('17:30:00.123456'))"); + verifySchema(result, schema("microsecond(time('17:30:00.123456'))", null, "integer")); + verifyDataRows(result, rows(123456)); + } + + @Test + public void testMinute() throws IOException { + JSONObject result = executeQuery("select minute(timestamp('2020-09-16 17:30:00'))"); + verifySchema(result, schema("minute(timestamp('2020-09-16 17:30:00'))", null, "integer")); + verifyDataRows(result, rows(30)); + + result = executeQuery("select minute(time('17:30:00'))"); + verifySchema(result, schema("minute(time('17:30:00'))", null, "integer")); + verifyDataRows(result, rows(30)); + } + + @Test + public void testMonth() throws IOException { + JSONObject result = executeQuery("select month(date('2020-09-16'))"); + verifySchema(result, schema("month(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(9)); + } + + @Test + public void testMonthName() throws IOException { + JSONObject result = executeQuery("select monthname(date('2020-09-16'))"); + verifySchema(result, schema("monthname(date('2020-09-16'))", null, "string")); + verifyDataRows(result, rows("September")); + } + + @Test + public void testQuarter() throws IOException { + JSONObject result = executeQuery("select quarter(date('2020-09-16'))"); + verifySchema(result, schema("quarter(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(3)); + } + + @Test + public void testSecond() throws IOException { + JSONObject result = executeQuery("select second(timestamp('2020-09-16 17:30:00'))"); + verifySchema(result, schema("second(timestamp('2020-09-16 17:30:00'))", null, "integer")); + verifyDataRows(result, rows(0)); + + result = executeQuery("select second(time('17:30:00'))"); + verifySchema(result, schema("second(time('17:30:00'))", null, "integer")); + verifyDataRows(result, rows(0)); + } + + @Test + public void testSubDate() throws IOException { + JSONObject result = + executeQuery("select subdate(timestamp('2020-09-16 17:30:00'), interval 1 day)"); + verifySchema(result, + schema("subdate(timestamp('2020-09-16 17:30:00'), interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15 17:30:00")); + + result = executeQuery("select subdate(date('2020-09-16'), 1)"); + verifySchema(result, schema("subdate(date('2020-09-16'), 1)", null, "date")); + verifyDataRows(result, rows("2020-09-15")); + } + + @Test + public void testTimeToSec() throws IOException { + JSONObject result = executeQuery("select time_to_sec(time('17:30:00'))"); + verifySchema(result, schema("time_to_sec(time('17:30:00'))", null, "long")); + verifyDataRows(result, rows(63000)); + } + + @Test + public void testToDays() throws IOException { + JSONObject result = executeQuery("select to_days(date('2020-09-16'))"); + verifySchema(result, schema("to_days(date('2020-09-16'))", null, "long")); + verifyDataRows(result, rows(738049)); + } + + @Test + public void testYear() throws IOException { + JSONObject result = executeQuery("select year(date('2020-09-16'))"); + verifySchema(result, schema("year(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(2020)); + } + + protected JSONObject executeQuery(String query) throws IOException { + Request request = new Request("POST", QUERY_API_ENDPOINT); + request.setJsonEntity(String.format(Locale.ROOT, "{\n" + " \"query\": \"%s\"\n" + "}", query)); + + RequestOptions.Builder restOptionsBuilder = RequestOptions.DEFAULT.toBuilder(); + restOptionsBuilder.addHeader("Content-Type", "application/json"); + request.setOptions(restOptionsBuilder); + + Response response = client().performRequest(request); + return new JSONObject(getResponseBody(response)); + } +} \ No newline at end of file From 7054a4b6c1efee9d724ae99a43ca766d1ce3a312 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 17 Sep 2020 16:41:44 -0700 Subject: [PATCH 30/42] add string input for date functions --- .../expression/datetime/DateTimeFunction.java | 110 ++++++++++-------- .../datetime/DateTimeFunctionTest.java | 43 ++++++- 2 files changed, 100 insertions(+), 53 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index ccad83c731..fa094925dd 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -123,8 +123,8 @@ private FunctionResolver date_sub() { */ private FunctionResolver day() { return define(BuiltinFunctionName.DAY.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING) ); } @@ -134,8 +134,8 @@ private FunctionResolver day() { */ private FunctionResolver dayName() { return define(BuiltinFunctionName.DAYNAME.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayName), - STRING, DATE) + impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, STRING) ); } @@ -144,8 +144,7 @@ private FunctionResolver dayName() { */ private FunctionResolver dayOfMonth() { return define(BuiltinFunctionName.DAYOFMONTH.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), - INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING) ); } @@ -155,8 +154,8 @@ private FunctionResolver dayOfMonth() { */ private FunctionResolver dayOfWeek() { return define(BuiltinFunctionName.DAYOFWEEK.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, STRING) ); } @@ -165,8 +164,8 @@ private FunctionResolver dayOfWeek() { */ private FunctionResolver dayOfYear() { return define(BuiltinFunctionName.DAYOFYEAR.getName(), - impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, STRING) ); } @@ -183,12 +182,9 @@ private FunctionResolver from_days() { */ private FunctionResolver hour() { return define(BuiltinFunctionName.HOUR.getName(), - impl(nullMissingHandling(DateTimeFunction::exprHour), - INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprHour), - INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprHour), - INTEGER, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIMESTAMP) ); } @@ -197,12 +193,9 @@ private FunctionResolver hour() { */ private FunctionResolver microsecond() { return define(BuiltinFunctionName.MICROSECOND.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), - INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), - INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), - INTEGER, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIMESTAMP) ); } @@ -211,12 +204,9 @@ private FunctionResolver microsecond() { */ private FunctionResolver minute() { return define(BuiltinFunctionName.MINUTE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprMinute), - INTEGER, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIMESTAMP) ); } @@ -225,8 +215,8 @@ private FunctionResolver minute() { */ private FunctionResolver month() { return define(BuiltinFunctionName.MONTH.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMonth), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, STRING) ); } @@ -235,8 +225,8 @@ private FunctionResolver month() { */ private FunctionResolver monthName() { return define(BuiltinFunctionName.MONTHNAME.getName(), - impl(nullMissingHandling(DateTimeFunction::exprMonthName), - STRING, DATE) + impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, DATE), + impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, STRING) ); } @@ -245,8 +235,8 @@ private FunctionResolver monthName() { */ private FunctionResolver quarter() { return define(BuiltinFunctionName.QUARTER.getName(), - impl(nullMissingHandling(DateTimeFunction::exprQuarter), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, STRING) ); } @@ -255,12 +245,9 @@ private FunctionResolver quarter() { */ private FunctionResolver second() { return define(BuiltinFunctionName.SECOND.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSecond), - INTEGER, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSecond), - INTEGER, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSecond), - INTEGER, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIMESTAMP) ); } @@ -302,8 +289,9 @@ private FunctionResolver time() { */ private FunctionResolver time_to_sec() { return define(BuiltinFunctionName.TIME_TO_SEC.getName(), - impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), - LONG, TIME) + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, DATETIME) ); } @@ -325,6 +313,7 @@ private FunctionResolver timestamp() { */ private FunctionResolver to_days() { return define(BuiltinFunctionName.TO_DAYS.getName(), + impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, STRING), impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATE), impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATETIME)); } @@ -334,8 +323,8 @@ private FunctionResolver to_days() { */ private FunctionResolver year() { return define(BuiltinFunctionName.YEAR.getName(), - impl(nullMissingHandling(DateTimeFunction::exprYear), - INTEGER, DATE) + impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, STRING) ); } @@ -358,6 +347,9 @@ private ExprValue exprDate(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprDayName(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprStringValue( date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); } @@ -369,8 +361,7 @@ private ExprValue exprDayName(ExprValue date) { */ private ExprValue exprDayOfMonth(ExprValue date) { if (date instanceof ExprStringValue) { - return new ExprIntegerValue( - new ExprDateValue(date.stringValue()).dateValue().getDayOfMonth()); + date = new ExprDateValue(date.stringValue()); } return new ExprIntegerValue(date.dateValue().getDayOfMonth()); } @@ -381,6 +372,9 @@ private ExprValue exprDayOfMonth(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfWeek(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprIntegerValue(date.dateValue().getDayOfWeek().getValue() == 7 ? 1 : date.dateValue().getDayOfWeek().getValue() + 1); } @@ -391,6 +385,9 @@ private ExprValue exprDayOfWeek(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfYear(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprIntegerValue(date.dateValue().getDayOfYear()); } @@ -437,6 +434,9 @@ private ExprValue exprMinute(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprMonth(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprIntegerValue(date.dateValue().getMonthValue()); } @@ -446,6 +446,9 @@ private ExprValue exprMonth(ExprValue date) { * @return ExprValue. */ private ExprValue exprMonthName(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprStringValue( date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); } @@ -457,6 +460,9 @@ private ExprValue exprMonthName(ExprValue date) { * @return ExprValue. */ private ExprValue exprQuarter(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprIntegerValue((date.dateValue().getMonthValue() % 3) == 0 ? (date.dateValue().getMonthValue() / 3) : ((date.dateValue().getMonthValue() / 3) + 1)); @@ -534,11 +540,14 @@ private ExprValue exprTimeToSec(ExprValue exprValue) { /** * To_days implementation for ExprValue. - * @param exprValue ExprValue of Date type. + * @param date ExprValue of Date type. * @return ExprValue. */ - private ExprValue exprToDays(ExprValue exprValue) { - return new ExprLongValue(exprValue.dateValue().toEpochDay() + DAYS_0000_TO_1970); + private ExprValue exprToDays(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } + return new ExprLongValue(date.dateValue().toEpochDay() + DAYS_0000_TO_1970); } /** @@ -547,6 +556,9 @@ private ExprValue exprToDays(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprYear(ExprValue date) { + if (date instanceof ExprStringValue) { + date = new ExprDateValue(date.stringValue()); + } return new ExprIntegerValue(date.dateValue().getYear()); } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 2a9ca92e7f..17cd61a171 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -143,6 +143,11 @@ public void day() { assertEquals(INTEGER, expression.type()); assertEquals("day(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(7), eval(expression)); + + expression = dsl.day(DSL.literal("2020-08-07")); + assertEquals(INTEGER, expression.type()); + assertEquals("day(\"2020-08-07\")", expression.toString()); + assertEquals(integerValue(7), eval(expression)); } @Test @@ -156,6 +161,11 @@ public void dayName() { assertEquals(STRING, expression.type()); assertEquals("dayname(DATE '2020-08-07')", expression.toString()); assertEquals(stringValue("Friday"), eval(expression)); + + expression = dsl.dayname(DSL.literal("2020-08-07")); + assertEquals(STRING, expression.type()); + assertEquals("dayname(\"2020-08-07\")", expression.toString()); + assertEquals(stringValue("Friday"), eval(expression)); } @Test @@ -192,6 +202,11 @@ public void dayOfWeek() { assertEquals(INTEGER, expression.type()); assertEquals("dayofweek(DATE '2020-08-09')", expression.toString()); assertEquals(integerValue(1), eval(expression)); + + expression = dsl.dayofweek(DSL.literal("2020-08-09")); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofweek(\"2020-08-09\")", expression.toString()); + assertEquals(integerValue(1), eval(expression)); } @Test @@ -205,6 +220,11 @@ public void dayOfYear() { assertEquals(INTEGER, expression.type()); assertEquals("dayofyear(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(220), eval(expression)); + + expression = dsl.dayofyear(DSL.literal("2020-08-07")); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofyear(\"2020-08-07\")", expression.toString()); + assertEquals(integerValue(220), eval(expression)); } @Test @@ -306,6 +326,11 @@ public void month() { assertEquals(INTEGER, expression.type()); assertEquals("month(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(8), eval(expression)); + + expression = dsl.month(DSL.literal("2020-08-07")); + assertEquals(INTEGER, expression.type()); + assertEquals("month(\"2020-08-07\")", expression.toString()); + assertEquals(integerValue(8), eval(expression)); } @Test @@ -319,6 +344,11 @@ public void monthName() { assertEquals(STRING, expression.type()); assertEquals("monthname(DATE '2020-08-07')", expression.toString()); assertEquals(stringValue("August"), eval(expression)); + + expression = dsl.monthname(DSL.literal("2020-08-07")); + assertEquals(STRING, expression.type()); + assertEquals("monthname(\"2020-08-07\")", expression.toString()); + assertEquals(stringValue("August"), eval(expression)); } @Test @@ -333,9 +363,9 @@ public void quarter() { assertEquals("quarter(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(3), eval(expression)); - expression = dsl.quarter(DSL.literal(new ExprDateValue("2020-12-07"))); + expression = dsl.quarter(DSL.literal("2020-12-07")); assertEquals(INTEGER, expression.type()); - assertEquals("quarter(DATE '2020-12-07')", expression.toString()); + assertEquals("quarter(\"2020-12-07\")", expression.toString()); assertEquals(integerValue(4), eval(expression)); } @@ -469,9 +499,9 @@ public void to_days() { assertEquals("to_days(DATE '2008-10-07')", expression.toString()); assertEquals(longValue(733687L), eval(expression)); - expression = dsl.to_days(DSL.literal(new ExprDateValue("1969-12-31"))); + expression = dsl.to_days(DSL.literal("1969-12-31")); assertEquals(LONG, expression.type()); - assertEquals("to_days(DATE '1969-12-31')", expression.toString()); + assertEquals("to_days(\"1969-12-31\")", expression.toString()); assertEquals(longValue(719527L), eval(expression)); } @@ -486,6 +516,11 @@ public void year() { assertEquals(INTEGER, expression.type()); assertEquals("year(DATE '2020-08-07')", expression.toString()); assertEquals(integerValue(2020), eval(expression)); + + expression = dsl.year(DSL.literal("2020-08-07")); + assertEquals(INTEGER, expression.type()); + assertEquals("year(\"2020-08-07\")", expression.toString()); + assertEquals(integerValue(2020), eval(expression)); } private ExprValue eval(Expression expression) { From 7e4c7266f0f10c72f66c513b45cf9fb77f733b11 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Fri, 18 Sep 2020 10:10:30 -0700 Subject: [PATCH 31/42] fix microsecond --- .../sql/data/model/ExprTimestampValue.java | 4 ++-- .../sql/expression/datetime/DateTimeFunction.java | 6 +++--- .../sql/data/model/DateTimeValueTest.java | 3 ++- .../sql/expression/datetime/DateTimeFunctionTest.java | 11 ++++++++--- .../sql/sql/DateTimeFunctionIT.java | 6 +++--- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java index a3dda267d0..3623e838c3 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTimestampValue.java @@ -44,7 +44,7 @@ public class ExprTimestampValue extends AbstractExprValue { * todo. only support timestamp in format yyyy-MM-dd HH:mm:ss. */ private static final DateTimeFormatter FORMATTER = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss[.n]"); + .ofPattern("yyyy-MM-dd HH:mm:ss[.SSSSSS]"); private static final DateTimeFormatter FORMATTER_WITNOUT_NANO = DateTimeFormatter .ofPattern("yyyy-MM-dd HH:mm:ss"); private final Instant timestamp; @@ -57,7 +57,7 @@ public ExprTimestampValue(String timestamp) { this.timestamp = LocalDateTime.parse(timestamp, FORMATTER).atZone(ZONE).toInstant(); } catch (DateTimeParseException e) { throw new SemanticCheckException(String.format("timestamp:%s in unsupported format, please " - + "use yyyy-MM-dd HH:mm:ss[.n]", timestamp)); + + "use yyyy-MM-dd HH:mm:ss[.SSSSSS]", timestamp)); } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index fa094925dd..dcd8d8b8f4 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -44,6 +44,7 @@ import java.time.LocalDate; import java.time.format.TextStyle; import java.util.Locale; +import java.util.concurrent.TimeUnit; import lombok.experimental.UtilityClass; /** @@ -414,9 +415,8 @@ private ExprValue exprHour(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprMicrosecond(ExprValue exprValue) { - return new ExprIntegerValue((exprValue.timeValue().getNano() == 0) ? 0 - : Integer.parseInt(CharMatcher.is('0') - .trimTrailingFrom(Integer.toString(exprValue.timeValue().getNano())))); + return new ExprIntegerValue( + TimeUnit.MICROSECONDS.convert(exprValue.timeValue().getNano(), TimeUnit.NANOSECONDS)); } /** diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java index 470bacabdb..cb07d9ae32 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java @@ -113,7 +113,8 @@ public void timestampInUnsupportedFormat() { assertThrows(SemanticCheckException.class, () -> new ExprTimestampValue("2020-07-07T01:01:01Z")); assertEquals( - "timestamp:2020-07-07T01:01:01Z in unsupported format, please use yyyy-MM-dd HH:mm:ss[.n]", + "timestamp:2020-07-07T01:01:01Z in unsupported format, " + + "please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", exception.getMessage()); } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 17cd61a171..8bacab808f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -281,15 +281,20 @@ public void microsecond() { assertEquals(integerValue(0), eval(expression)); assertEquals("microsecond(TIME '01:02:03')", expression.toString()); - expression = dsl.microsecond(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03.123456"))); + expression = dsl.microsecond(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03.000010"))); assertEquals(INTEGER, expression.type()); - assertEquals(integerValue(123456), expression.valueOf(env)); - assertEquals("microsecond(TIMESTAMP '2020-08-17 01:02:03.123456')", expression.toString()); + assertEquals(integerValue(10), expression.valueOf(env)); + assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.00001')", expression.toString()); expression = dsl.microsecond(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03.123456"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(123456), expression.valueOf(env)); assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString()); + + expression = dsl.microsecond(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03.000010"))); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(10), expression.valueOf(env)); + assertEquals("microsecond(TIMESTAMP '2020-08-17 01:02:03.000010')", expression.toString()); } @Test diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java index 2b7481b01e..e93421d505 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -112,9 +112,9 @@ public void testMicrosecond() throws IOException { verifySchema(result, schema("microsecond(timestamp('2020-09-16 17:30:00.123456'))", null, "integer")); verifyDataRows(result, rows(123456)); - result = executeQuery("select microsecond(time('17:30:00.123456'))"); - verifySchema(result, schema("microsecond(time('17:30:00.123456'))", null, "integer")); - verifyDataRows(result, rows(123456)); + result = executeQuery("select microsecond(time('17:30:00.000010'))"); + verifySchema(result, schema("microsecond(time('17:30:00.000010'))", null, "integer")); + verifyDataRows(result, rows(10)); } @Test From f0a16ce384ee021f54b2de091cb33897f48335de Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Fri, 18 Sep 2020 11:41:47 -0700 Subject: [PATCH 32/42] update doc --- .../expression/datetime/DateTimeFunction.java | 17 ++++++++++------- docs/user/dql/functions.rst | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index dcd8d8b8f4..1d332ffb56 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -40,7 +40,6 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; -import com.google.common.base.CharMatcher; import java.time.LocalDate; import java.time.format.TextStyle; import java.util.Locale; @@ -101,9 +100,11 @@ private FunctionResolver date() { } /** - * Extracts the date part of a date and time value. - * Also to construct a date type. The supported signatures: - * STRING/DATE/DATETIME/TIMESTAMP -> DATE + * Specify a start date and subtract a temporal amount to the date. + * The return type depends on the date type and the interval unit. Detailed supported signatures: + * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (DATE, LONG) -> DATE + * (DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver date_sub() { return define(BuiltinFunctionName.DATE_SUB.getName(), @@ -253,9 +254,11 @@ private FunctionResolver second() { } /** - * Extracts the date part of a date and time value. - * Also to construct a date type. The supported signatures: - * STRING/DATE/DATETIME/TIMESTAMP -> DATE + * Specify a start date and subtract a temporal amount to the date. + * The return type depends on the date type and the interval unit. Detailed supported signatures: + * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (DATE, LONG) -> DATE + * (DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver subdate() { return define(BuiltinFunctionName.SUBDATE.getName(), diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index fb9a275c17..9ba90f94f4 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -353,7 +353,7 @@ DAY Description ----------- -Usage: day(date) extracts the day of the month for date, in the range 1 to 31, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero day part. +Usage: day(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. Argument type: DATE @@ -399,7 +399,7 @@ DAYOFMONTH Description ----------- -Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero day part. +Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. Argument type: DATE @@ -820,7 +820,7 @@ MONTH Description ----------- -Usage: month(date) returns the month for date, in the range 1 to 12 for January to December, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero month part. +Usage: month(date) returns the month for date, in the range 1 to 12 for January to December. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. Argument type: DATE From b757335ed319003d6b76c23f81f24176c7c48781 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Fri, 18 Sep 2020 15:05:00 -0700 Subject: [PATCH 33/42] add date_add --- .../sql/expression/DSL.java | 4 ++ .../expression/datetime/DateTimeFunction.java | 47 +++++++++++++++++++ .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 45 ++++++++++++++++++ docs/user/dql/functions.rst | 41 +++++++++++++++- .../sql/sql/DateTimeFunctionIT.java | 13 +++++ ppl/src/main/antlr/OpenDistroPPLLexer.g4 | 1 + ppl/src/main/antlr/OpenDistroPPLParser.g4 | 2 +- sql/src/main/antlr/OpenDistroSQLLexer.g4 | 1 + sql/src/main/antlr/OpenDistroSQLParser.g4 | 2 +- 10 files changed, 153 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java index 30100e0a0d..3d62359524 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/DSL.java @@ -249,6 +249,10 @@ public FunctionExpression date(Expression... expressions) { return function(BuiltinFunctionName.DATE, expressions); } + public FunctionExpression date_add(Expression... expressions) { + return function(BuiltinFunctionName.DATE_ADD, expressions); + } + public FunctionExpression date_sub(Expression... expressions) { return function(BuiltinFunctionName.DATE_SUB, expressions); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 1d332ffb56..d412f001c6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -64,6 +64,7 @@ public class DateTimeFunction { */ public void register(BuiltinFunctionRepository repository) { repository.register(date()); + repository.register(date_add()); repository.register(date_sub()); repository.register(day()); repository.register(dayName()); @@ -99,6 +100,27 @@ private FunctionResolver date() { impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP)); } + /** + * Specify a start date and add a temporal amount to the date. + * The return type depends on the date type and the interval unit. Detailed supported signatures: + * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (DATE, LONG) -> DATE + * (DATETIME/TIMESTAMP, LONG) -> DATETIME + */ + private FunctionResolver date_add() { + return define(BuiltinFunctionName.DATE_ADD.getName(), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), + DATETIME, DATETIME, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), + DATETIME, TIMESTAMP, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATE, DATE, LONG), + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, DATETIME, LONG), + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG) + ); + } + /** * Specify a start date and subtract a temporal amount to the date. * The return type depends on the date type and the interval unit. Detailed supported signatures: @@ -332,6 +354,31 @@ private FunctionResolver year() { ); } + /** + * ADDDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param expr ExprValue of Interval type, the temporal amount to add. + * @return Date/Datetime resulted from expr added to date. + */ + private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) { + return new ExprDatetimeValue(date.datetimeValue().plus(expr.intervalValue())); + } + + /** + * ADDDATE function implementation for ExprValue. + * + * @param date ExprValue of Date/Datetime/Timestamp type. + * @param days ExprValue of Long type, representing the number of days to add. + * @return Date/Datetime resulted from days added to date. + */ + private ExprValue exprAddDateDays(ExprValue date, ExprValue days) { + if (date instanceof ExprDateValue) { + return new ExprDateValue(date.dateValue().plusDays(days.longValue())); + } + return new ExprDatetimeValue(date.datetimeValue().plusDays(days.longValue())); + } + /** * Date implementation for ExprValue. * @param exprValue ExprValue of Date type or String type. diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 1a2fa819c7..415b5d9b88 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -52,6 +52,7 @@ public enum BuiltinFunctionName { * Date and Time Functions. */ DATE(FunctionName.of("date")), + DATE_ADD(FunctionName.of("date_add")), DATE_SUB(FunctionName.of("date_sub")), DAY(FunctionName.of("day")), DAYNAME(FunctionName.of("dayname")), diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 8bacab808f..d3e6fa7df4 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -86,6 +86,51 @@ public void date() { assertEquals("date(DATE '2020-08-17')", expr.toString()); } + @Test + public void date_add() { + FunctionExpression expr = dsl.date_add(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); + assertEquals(DATE, expr.type()); + assertEquals(new ExprDateValue("2020-09-02"), expr.valueOf(env)); + assertEquals("date_add(date(\"2020-08-26\"), 7)", expr.toString()); + + expr = dsl.date_add(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-09-02 12:05:00"), expr.valueOf(env)); + assertEquals("date_add(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + + expr = dsl.date_add( + dsl.date(DSL.literal("2020-08-26")), dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); + assertEquals("date_add(date(\"2020-08-26\"), interval(1, \"hour\"))", expr.toString()); + + when(nullRef.type()).thenReturn(DATE); + assertEquals(nullValue(), eval(dsl.date_add(nullRef, DSL.literal(1L)))); + assertEquals(nullValue(), + eval(dsl.date_add(nullRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(missingRef.type()).thenReturn(DATE); + assertEquals(missingValue(), eval(dsl.date_add(missingRef, DSL.literal(1L)))); + assertEquals(missingValue(), + eval(dsl.date_add(missingRef, dsl.interval(DSL.literal(1), DSL.literal("month"))))); + + when(nullRef.type()).thenReturn(LONG); + when(missingRef.type()).thenReturn(LONG); + assertEquals(nullValue(), eval(dsl.date_add(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_add(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(INTERVAL); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(nullValue(), eval(dsl.date_add(dsl.date(DSL.literal("2020-08-26")), nullRef))); + assertEquals(missingValue(), + eval(dsl.date_add(dsl.date(DSL.literal("2020-08-26")), missingRef))); + + when(nullRef.type()).thenReturn(DATE); + when(missingRef.type()).thenReturn(INTERVAL); + assertEquals(missingValue(), eval(dsl.date_add(nullRef, missingRef))); + } + @Test public void date_sub() { FunctionExpression expr = dsl.date_sub(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7)); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 9ba90f94f4..06e5c0dc1e 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -323,6 +323,35 @@ Specifications: 1. DATE_FORMAT(DATE, STRING) -> STRING 2. DATE_FORMAT(DATE, STRING, STRING) -> STRING +DATE_ADD +===== + +Description +----------- + +Usage: date_add(date, INTERVAL expr unit) adds the time interval expr to date + +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL + +Return type: + +(DATE, DATE INTERVAL) -> DATE +(DATE, TIME INTERVAL) -> DATETIME +(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + +Synonyms: ADDDATE + +Example:: + + od> SELECT DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR), DATE_ADD(DATE('2020-08-26'), 1) + fetched rows / total rows = 1/1 + +-------------------------------------------------+-----------------------------------+ + | DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR) | DATE_ADD(DATE('2020-08-26'), 1) | + |-------------------------------------------------+-----------------------------------| + | 2020-08-26 01:00:00 | 2020-08-27 | + +-------------------------------------------------+-----------------------------------+ + + DATE_SUB ===== @@ -333,7 +362,11 @@ Usage: date_sub(date, INTERVAL expr unit) subtracts the time interval expr from Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL -Return type: (DATE, DATE INTERVAL) -> DATE (DATE, TIME INTERVAL) -> DATETIME (DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +Return type: + +(DATE, DATE INTERVAL) -> DATE +(DATE, TIME INTERVAL) -> DATETIME +(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME Synonyms: SUBDATE @@ -1214,7 +1247,11 @@ Usage: subdate(date,INTERVAL expr unit) subtracts time interval from date. subda Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL -Return type: (DATE, DATE INTERVAL) -> DATE (DATE, TIME INTERVAL) -> DATETIME (DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +Return type: + +(DATE, DATE INTERVAL) -> DATE +(DATE, TIME INTERVAL) -> DATETIME +(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME Synonyms: DATE_SUB diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java index e93421d505..9e6953798e 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -40,6 +40,19 @@ public void init() throws Exception { TestUtils.enableNewQueryEngine(client()); } + @Test + public void testDateAdd() throws IOException { + JSONObject result = + executeQuery("select date_add(timestamp('2020-09-16 17:30:00'), interval 1 day)"); + verifySchema(result, + schema("date_add(timestamp('2020-09-16 17:30:00'), interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17 17:30:00")); + + result = executeQuery("select date_add(date('2020-09-16'), 1)"); + verifySchema(result, schema("date_add(date('2020-09-16'), 1)", null, "date")); + verifyDataRows(result, rows("2020-09-17")); + } + @Test public void testDateSub() throws IOException { JSONObject result = diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index e50d493f5c..f76e2508ff 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -196,6 +196,7 @@ TAN: 'TAN'; // DATE AND TIME FUNCTIONS DATE: 'DATE'; +DATE_ADD: 'DATE_ADD'; DATE_SUB: 'DATE_SUB'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 9a961c1bf3..5875fe0d5b 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -226,7 +226,7 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR + : DATE | DATE_ADD | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | TO_DAYS | YEAR ; diff --git a/sql/src/main/antlr/OpenDistroSQLLexer.g4 b/sql/src/main/antlr/OpenDistroSQLLexer.g4 index 66dab3414d..6e83ca9102 100644 --- a/sql/src/main/antlr/OpenDistroSQLLexer.g4 +++ b/sql/src/main/antlr/OpenDistroSQLLexer.g4 @@ -173,6 +173,7 @@ CRC32: 'CRC32'; CURDATE: 'CURDATE'; DATE: 'DATE'; DATE_FORMAT: 'DATE_FORMAT'; +DATE_ADD: 'DATE_ADD'; DATE_SUB: 'DATE_SUB'; DAYOFMONTH: 'DAYOFMONTH'; DAYOFWEEK: 'DAYOFWEEK'; diff --git a/sql/src/main/antlr/OpenDistroSQLParser.g4 b/sql/src/main/antlr/OpenDistroSQLParser.g4 index e6d4eb87b3..5b0f634f48 100644 --- a/sql/src/main/antlr/OpenDistroSQLParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLParser.g4 @@ -230,7 +230,7 @@ trigonometricFunctionName ; dateTimeFunctionName - : DATE | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR + : DATE | DATE_ADD | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | HOUR | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC | TIMESTAMP | TO_DAYS | YEAR ; From 1a44c36c211c4e15caf6917cac7f6dc3791129ea Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Fri, 18 Sep 2020 17:44:39 -0700 Subject: [PATCH 34/42] address PR comments --- .../sql/data/model/ExprDatetimeValue.java | 8 +++----- .../sql/expression/datetime/DateTimeFunction.java | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java index 4ed25e6dcb..aad4e0ed7e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDatetimeValue.java @@ -80,11 +80,9 @@ public boolean equal(ExprValue other) { @Override public String value() { - return datetime.getNano() == 0 - ? String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), - DateTimeFormatter.ISO_TIME.format(datetime.truncatedTo(ChronoUnit.SECONDS))) - : String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), - DateTimeFormatter.ISO_TIME.format(datetime)); + return String.format("%s %s", DateTimeFormatter.ISO_DATE.format(datetime), + DateTimeFormatter.ISO_TIME.format((datetime.getNano() == 0) + ? datetime.truncatedTo(ChronoUnit.SECONDS) : datetime)); } @Override diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index d412f001c6..c0b03dc1cf 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -426,8 +426,7 @@ private ExprValue exprDayOfWeek(ExprValue date) { if (date instanceof ExprStringValue) { date = new ExprDateValue(date.stringValue()); } - return new ExprIntegerValue(date.dateValue().getDayOfWeek().getValue() == 7 ? 1 - : date.dateValue().getDayOfWeek().getValue() + 1); + return new ExprIntegerValue((date.dateValue().getDayOfWeek().getValue() % 7) + 1); } /** @@ -513,9 +512,8 @@ private ExprValue exprQuarter(ExprValue date) { if (date instanceof ExprStringValue) { date = new ExprDateValue(date.stringValue()); } - return new ExprIntegerValue((date.dateValue().getMonthValue() % 3) == 0 - ? (date.dateValue().getMonthValue() / 3) - : ((date.dateValue().getMonthValue() / 3) + 1)); + int month = date.dateValue().getMonthValue(); + return new ExprIntegerValue((month / 3) + ((month % 3) == 0 ? 0 : 1)); } /** From 20acde3d0f51681c78a8702dee9af5587081aba6 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 22 Sep 2020 17:03:16 -0700 Subject: [PATCH 35/42] update tests & doc --- .../expression/datetime/DateTimeFunction.java | 325 +++++++++++----- .../datetime/DateTimeFunctionTest.java | 115 ++++++ docs/user/dql/functions.rst | 77 ++-- .../sql/ppl/DateTimeFunctionIT.java | 358 ++++++++++++++++++ .../sql/sql/DateTimeFunctionIT.java | 106 ++++++ 5 files changed, 846 insertions(+), 135 deletions(-) create mode 100644 integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index c0b03dc1cf..3ff07dc834 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -37,10 +37,15 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; +import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.time.format.TextStyle; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -103,13 +108,14 @@ private FunctionResolver date() { /** * Specify a start date and add a temporal amount to the date. * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME * (DATE, LONG) -> DATE - * (DATETIME/TIMESTAMP, LONG) -> DATETIME + * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver date_add() { return define(BuiltinFunctionName.DATE_ADD.getName(), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), + DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATETIME, INTERVAL), @@ -117,20 +123,22 @@ private FunctionResolver date_add() { DATETIME, TIMESTAMP, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATE, DATE, LONG), impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG) + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG), + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, STRING, LONG) ); } /** * Specify a start date and subtract a temporal amount to the date. * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME * (DATE, LONG) -> DATE - * (DATETIME/TIMESTAMP, LONG) -> DATETIME + * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver date_sub() { return define(BuiltinFunctionName.DATE_SUB.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATETIME, INTERVAL), @@ -138,63 +146,77 @@ private FunctionResolver date_sub() { DATETIME, TIMESTAMP, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, STRING, LONG) ); } /** - * DAY(DATE). return the day of the month (1-31). + * DAY(STRING/DATE/DATETIME/TIMESTAMP). return the day of the month (1-31). */ private FunctionResolver day() { return define(BuiltinFunctionName.DAY.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING) ); } /** - * DAYNAME(DATE). return the name of the weekday for date, including Monday, Tuesday, Wednesday, + * DAYNAME(STRING/DATE/DATETIME/TIMESTAMP). + * return the name of the weekday for date, including Monday, Tuesday, Wednesday, * Thursday, Friday, Saturday and Sunday. */ private FunctionResolver dayName() { return define(BuiltinFunctionName.DAYNAME.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprDayName), STRING, STRING) ); } /** - * DAYOFMONTH(DATE). return the day of the month (1-31). + * DAYOFMONTH(STRING/DATE/DATETIME/TIMESTAMP). return the day of the month (1-31). */ private FunctionResolver dayOfMonth() { return define(BuiltinFunctionName.DAYOFMONTH.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING) ); } /** - * DAYOFWEEK(DATE). return the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). + * DAYOFWEEK(STRING/DATE/DATETIME/TIMESTAMP). + * return the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). */ private FunctionResolver dayOfWeek() { return define(BuiltinFunctionName.DAYOFWEEK.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, STRING) ); } /** - * DAYOFYEAR(DATE). return the day of the year for date (1-366). + * DAYOFYEAR(STRING/DATE/DATETIME/TIMESTAMP). + * return the day of the year for date (1-366). */ private FunctionResolver dayOfYear() { return define(BuiltinFunctionName.DAYOFYEAR.getName(), impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprDayOfYear), INTEGER, STRING) ); } /** - * FROM_DAYS(DATE). return the date value given the day number N. + * FROM_DAYS(LONG). return the date value given the day number N. */ private FunctionResolver from_days() { return define(BuiltinFunctionName.FROM_DAYS.getName(), @@ -202,10 +224,11 @@ private FunctionResolver from_days() { } /** - * HOUR(TIME). return the hour value for time. + * HOUR(STRING/TIME/DATETIME/TIMESTAMP). return the hour value for time. */ private FunctionResolver hour() { return define(BuiltinFunctionName.HOUR.getName(), + impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIMESTAMP) @@ -213,10 +236,11 @@ private FunctionResolver hour() { } /** - * MICROSECOND(TIME). return the microsecond value for time. + * MICROSECOND(STRING/TIME/DATETIME/TIMESTAMP). return the microsecond value for time. */ private FunctionResolver microsecond() { return define(BuiltinFunctionName.MICROSECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprMicrosecond), INTEGER, TIMESTAMP) @@ -224,10 +248,11 @@ private FunctionResolver microsecond() { } /** - * MINUTE(TIME). return the minute value for time. + * MINUTE(STRING/TIME/DATETIME/TIMESTAMP). return the minute value for time. */ private FunctionResolver minute() { return define(BuiltinFunctionName.MINUTE.getName(), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIMESTAMP) @@ -235,40 +260,47 @@ private FunctionResolver minute() { } /** - * MONTH(DATE). return the month for date (1-12). + * MONTH(STRING/DATE/DATETIME/TIMESTAMP). return the month for date (1-12). */ private FunctionResolver month() { return define(BuiltinFunctionName.MONTH.getName(), impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprMonth), INTEGER, STRING) ); } /** - * MONTHNAME(DATE). return the full name of the month for date. + * MONTHNAME(STRING/DATE/DATETIME/TIMESTAMP). return the full name of the month for date. */ private FunctionResolver monthName() { return define(BuiltinFunctionName.MONTHNAME.getName(), impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, DATE), + impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprMonthName), STRING, STRING) ); } /** - * QUARTER(DATE). return the month for date (1-4). + * QUARTER(STRING/DATE/DATETIME/TIMESTAMP). return the month for date (1-4). */ private FunctionResolver quarter() { return define(BuiltinFunctionName.QUARTER.getName(), impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprQuarter), INTEGER, STRING) ); } /** - * SECOND(TIME). return the second value for time. + * SECOND(STRING/TIME/DATETIME/TIMESTAMP). return the second value for time. */ private FunctionResolver second() { return define(BuiltinFunctionName.SECOND.getName(), + impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIMESTAMP) @@ -278,13 +310,14 @@ private FunctionResolver second() { /** * Specify a start date and subtract a temporal amount to the date. * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME * (DATE, LONG) -> DATE - * (DATETIME/TIMESTAMP, LONG) -> DATETIME + * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver subdate() { return define(BuiltinFunctionName.SUBDATE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), + DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATETIME, INTERVAL), @@ -292,7 +325,8 @@ private FunctionResolver subdate() { DATETIME, TIMESTAMP, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG) + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG), + impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, STRING, LONG) ); } @@ -311,10 +345,11 @@ private FunctionResolver time() { } /** - * TIME_TO_SEC(TIME). return the time argument, converted to seconds. + * TIME_TO_SEC(STRING/TIME/DATETIME/TIMESTAMP). return the time argument, converted to seconds. */ private FunctionResolver time_to_sec() { return define(BuiltinFunctionName.TIME_TO_SEC.getName(), + impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, TIME), impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprTimeToSec), LONG, DATETIME) @@ -335,21 +370,24 @@ private FunctionResolver timestamp() { } /** - * TO_DAYS(DATE). return the day number of the given date. + * TO_DAYS(STRING/DATE/DATETIME/TIMESTAMP). return the day number of the given date. */ private FunctionResolver to_days() { return define(BuiltinFunctionName.TO_DAYS.getName(), impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, STRING), + impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATE), impl(nullMissingHandling(DateTimeFunction::exprToDays), LONG, DATETIME)); } /** - * YEAR(DATE). return the year for date (1000-9999). + * YEAR(STRING/DATE/DATETIME/TIMESTAMP). return the year for date (1000-9999). */ private FunctionResolver year() { return define(BuiltinFunctionName.YEAR.getName(), impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, DATE), + impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, TIMESTAMP), impl(nullMissingHandling(DateTimeFunction::exprYear), INTEGER, STRING) ); } @@ -357,30 +395,35 @@ private FunctionResolver year() { /** * ADDDATE function implementation for ExprValue. * - * @param date ExprValue of Date/Datetime/Timestamp type. + * @param date ExprValue of String/Date/Datetime/Timestamp type. * @param expr ExprValue of Interval type, the temporal amount to add. - * @return Date/Datetime resulted from expr added to date. + * @return Datetime resulted from expr added to date. */ private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) { - return new ExprDatetimeValue(date.datetimeValue().plus(expr.intervalValue())); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprDatetimeValue(exprValue.datetimeValue().plus(expr.intervalValue())); } /** * ADDDATE function implementation for ExprValue. * - * @param date ExprValue of Date/Datetime/Timestamp type. + * @param date ExprValue of String/Date/Datetime/Timestamp type. * @param days ExprValue of Long type, representing the number of days to add. * @return Date/Datetime resulted from days added to date. */ private ExprValue exprAddDateDays(ExprValue date, ExprValue days) { - if (date instanceof ExprDateValue) { - return new ExprDateValue(date.dateValue().plusDays(days.longValue())); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + if (exprValue instanceof ExprDateValue) { + return new ExprDateValue(exprValue.dateValue().plusDays(days.longValue())); } - return new ExprDatetimeValue(date.datetimeValue().plusDays(days.longValue())); + return new ExprDatetimeValue(exprValue.datetimeValue().plusDays(days.longValue())); } /** * Date implementation for ExprValue. + * * @param exprValue ExprValue of Date type or String type. * @return ExprValue. */ @@ -394,54 +437,56 @@ private ExprValue exprDate(ExprValue exprValue) { /** * Name of the Weekday implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprDayName(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; return new ExprStringValue( - date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); + exprValue.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); } /** * Day of Month implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprDayOfMonth(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - return new ExprIntegerValue(date.dateValue().getDayOfMonth()); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprIntegerValue(exprValue.dateValue().getDayOfMonth()); } /** * Day of Week implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprDayOfWeek(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - return new ExprIntegerValue((date.dateValue().getDayOfWeek().getValue() % 7) + 1); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprIntegerValue((exprValue.dateValue().getDayOfWeek().getValue() % 7) + 1); } /** * Day of Year implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprDayOfYear(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - return new ExprIntegerValue(date.dateValue().getDayOfYear()); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprIntegerValue(exprValue.dateValue().getDayOfYear()); } - /** From_days implementation for ExprValue. + /** + * From_days implementation for ExprValue. + * * @param exprValue Day number N. * @return ExprValue. */ @@ -451,108 +496,124 @@ private ExprValue exprFromDays(ExprValue exprValue) { /** * Hour implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * + * @param time ExprValue of Time/String type. * @return ExprValue. */ - private ExprValue exprHour(ExprValue exprValue) { + private ExprValue exprHour(ExprValue time) { + ExprValue exprValue = + time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprIntegerValue(exprValue.timeValue().getHour()); } /** * Microsecond implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * + * @param time ExprValue of Time/String type. * @return ExprValue. */ - private ExprValue exprMicrosecond(ExprValue exprValue) { + private ExprValue exprMicrosecond(ExprValue time) { + ExprValue exprValue = + time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprIntegerValue( TimeUnit.MICROSECONDS.convert(exprValue.timeValue().getNano(), TimeUnit.NANOSECONDS)); } /** * Minute implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * + * @param time ExprValue of Time/String type. * @return ExprValue. */ - private ExprValue exprMinute(ExprValue exprValue) { + private ExprValue exprMinute(ExprValue time) { + ExprValue exprValue = + time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprIntegerValue(exprValue.timeValue().getMinute()); } /** * Month for date implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprMonth(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - return new ExprIntegerValue(date.dateValue().getMonthValue()); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprIntegerValue(exprValue.dateValue().getMonthValue()); } /** * Name of the Month implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprMonthName(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; return new ExprStringValue( - date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); + exprValue.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); } /** * Quarter for date implementation for ExprValue. * - * @param date ExprValue of Date type. + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprQuarter(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - int month = date.dateValue().getMonthValue(); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + int month = exprValue.dateValue().getMonthValue(); return new ExprIntegerValue((month / 3) + ((month % 3) == 0 ? 0 : 1)); } /** * Second implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * + * @param time ExprValue of Time/String type. * @return ExprValue. */ - private ExprValue exprSecond(ExprValue exprValue) { + private ExprValue exprSecond(ExprValue time) { + ExprValue exprValue = + time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprIntegerValue(exprValue.timeValue().getSecond()); } /** * SUBDATE function implementation for ExprValue. * - * @param date ExprValue of Date/Datetime/Timestamp type. + * @param date ExprValue of String/Date/Datetime/Timestamp type. * @param days ExprValue of Long type, representing the number of days to subtract. * @return Date/Datetime resulted from days subtracted to date. */ private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { - if (date instanceof ExprDateValue) { - return new ExprDateValue(date.dateValue().minusDays(days.longValue())); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + if (exprValue instanceof ExprDateValue) { + return new ExprDateValue(exprValue.dateValue().minusDays(days.longValue())); } else { - return new ExprDatetimeValue(date.datetimeValue().minusDays(days.longValue())); + return new ExprDatetimeValue(exprValue.datetimeValue().minusDays(days.longValue())); } } /** * SUBDATE function implementation for ExprValue. * - * @param date ExprValue of Date/Datetime/Timestamp type. + * @param date ExprValue of String/Date/Datetime/Timestamp type. * @param expr ExprValue of Interval type, the temporal amount to subtract. - * @return Date/Datetime resulted from expr subtracted to date. + * @return Datetime resulted from expr subtracted to date. */ private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { - return new ExprDatetimeValue(date.datetimeValue().minus(expr.intervalValue())); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprDatetimeValue(exprValue.datetimeValue().minus(expr.intervalValue())); } /** * Time implementation for ExprValue. + * * @param exprValue ExprValue of Time type or String. * @return ExprValue. */ @@ -566,6 +627,7 @@ private ExprValue exprTime(ExprValue exprValue) { /** * Timestamp implementation for ExprValue. + * * @param exprValue ExprValue of Timestamp type or String type. * @return ExprValue. */ @@ -579,34 +641,103 @@ private ExprValue exprTimestamp(ExprValue exprValue) { /** * Time To Sec implementation for ExprValue. - * @param exprValue ExprValue of Time type. + * + * @param time ExprValue of Time/String type. * @return ExprValue. */ - private ExprValue exprTimeToSec(ExprValue exprValue) { + private ExprValue exprTimeToSec(ExprValue time) { + ExprValue exprValue = + time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprLongValue(exprValue.timeValue().toSecondOfDay()); } /** * To_days implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprToDays(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); - } - return new ExprLongValue(date.dateValue().toEpochDay() + DAYS_0000_TO_1970); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprLongValue(exprValue.dateValue().toEpochDay() + DAYS_0000_TO_1970); } /** * Year for date implementation for ExprValue. - * @param date ExprValue of Date type. + * + * @param date ExprValue of Date/String type. * @return ExprValue. */ private ExprValue exprYear(ExprValue date) { - if (date instanceof ExprStringValue) { - date = new ExprDateValue(date.stringValue()); + ExprValue exprValue = + date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; + return new ExprIntegerValue(exprValue.dateValue().getYear()); + } + + /** + * Returns date, time or datetime for string value. + * + * @param string ExprValue of String type. + * @return ExprValue. + */ + private ExprValue getStringValue(String string) { + if (isValidDateTime(string)) { + return new ExprDatetimeValue(string); + } else if (isValidDate(string)) { + return new ExprDateValue(string); + } else if (isValidTime(string)) { + return new ExprTimeValue(string); + } + throw new SemanticCheckException(String.format("%s in unsupported format, please " + + "use yyyy-MM-dd HH:mm:ss[.SSSSSS]", string)); + } + + /** + * Returns true if string is in datetime format. + * + * @param datetime ExprValue of String type. + * @return ExprValue. + */ + private boolean isValidDateTime(String datetime) { + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss[.SSSSSS]"); + try { + LocalDateTime.parse(datetime, formatter); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + + /** + * Returns true if string is in date format. + * + * @param date ExprValue of String type. + * @return ExprValue. + */ + private boolean isValidDate(String date) { + try { + LocalDate.parse(date); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + + /** + * Returns true if string is in time format. + * + * @param time ExprValue of String type. + * @return ExprValue. + */ + private boolean isValidTime(String time) { + try { + LocalTime.parse(time); + return true; + } catch (DateTimeParseException e) { + return false; } - return new ExprIntegerValue(date.dateValue().getYear()); } + } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index d3e6fa7df4..e7f0a737ea 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -31,6 +31,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; @@ -39,6 +40,7 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; +import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.ExpressionTestBase; @@ -93,6 +95,11 @@ public void date_add() { assertEquals(new ExprDateValue("2020-09-02"), expr.valueOf(env)); assertEquals("date_add(date(\"2020-08-26\"), 7)", expr.toString()); + expr = dsl.date_add(DSL.literal("2020-08-26 12:05:00"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-09-02 12:05:00"), expr.valueOf(env)); + assertEquals("date_add(\"2020-08-26 12:05:00\", 7)", expr.toString()); + expr = dsl.date_add(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); assertEquals(DATETIME, expr.type()); assertEquals(new ExprDatetimeValue("2020-09-02 12:05:00"), expr.valueOf(env)); @@ -104,6 +111,12 @@ public void date_add() { assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); assertEquals("date_add(date(\"2020-08-26\"), interval(1, \"hour\"))", expr.toString()); + expr = dsl + .date_add(DSL.literal("2020-08-26"), dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); + assertEquals("date_add(\"2020-08-26\", interval(1, \"hour\"))", expr.toString()); + when(nullRef.type()).thenReturn(DATE); assertEquals(nullValue(), eval(dsl.date_add(nullRef, DSL.literal(1L)))); assertEquals(nullValue(), @@ -138,11 +151,21 @@ public void date_sub() { assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); assertEquals("date_sub(date(\"2020-08-26\"), 7)", expr.toString()); + expr = dsl.date_sub(DSL.literal("2020-08-26"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); + assertEquals("date_sub(\"2020-08-26\", 7)", expr.toString()); + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); assertEquals(DATETIME, expr.type()); assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + expr = dsl.date_sub(DSL.literal("2020-08-26 12:05:00"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); + assertEquals("date_sub(\"2020-08-26 12:05:00\", 7)", expr.toString()); + expr = dsl.date_sub(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), dsl.interval(DSL.literal(1), DSL.literal("hour"))); assertEquals(DATETIME, expr.type()); @@ -150,6 +173,13 @@ public void date_sub() { assertEquals("date_sub(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", expr.toString()); + expr = dsl.date_sub(DSL.literal("2020-08-26 12:05:00"), + dsl.interval(DSL.literal(1), DSL.literal("year"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2019-08-26 12:05:00"), expr.valueOf(env)); + assertEquals("date_sub(\"2020-08-26 12:05:00\", interval(1, \"year\"))", + expr.toString()); + when(nullRef.type()).thenReturn(DATE); assertEquals(nullValue(), eval(dsl.date_sub(nullRef, DSL.literal(1L)))); assertEquals(nullValue(), @@ -252,6 +282,11 @@ public void dayOfWeek() { assertEquals(INTEGER, expression.type()); assertEquals("dayofweek(\"2020-08-09\")", expression.toString()); assertEquals(integerValue(1), eval(expression)); + + expression = dsl.dayofweek(DSL.literal("2020-08-09 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofweek(\"2020-08-09 01:02:03\")", expression.toString()); + assertEquals(integerValue(1), eval(expression)); } @Test @@ -270,6 +305,11 @@ public void dayOfYear() { assertEquals(INTEGER, expression.type()); assertEquals("dayofyear(\"2020-08-07\")", expression.toString()); assertEquals(integerValue(220), eval(expression)); + + expression = dsl.dayofyear(DSL.literal("2020-08-07 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals("dayofyear(\"2020-08-07 01:02:03\")", expression.toString()); + assertEquals(integerValue(220), eval(expression)); } @Test @@ -297,6 +337,11 @@ public void hour() { assertEquals(integerValue(1), eval(expression)); assertEquals("hour(TIME '01:02:03')", expression.toString()); + expression = dsl.hour(DSL.literal("01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(1), eval(expression)); + assertEquals("hour(\"01:02:03\")", expression.toString()); + expression = dsl.hour(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(1), expression.valueOf(env)); @@ -306,6 +351,11 @@ public void hour() { assertEquals(INTEGER, expression.type()); assertEquals(integerValue(1), expression.valueOf(env)); assertEquals("hour(DATETIME '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.hour(DSL.literal("2020-08-17 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(1), expression.valueOf(env)); + assertEquals("hour(\"2020-08-17 01:02:03\")", expression.toString()); } @Test @@ -326,6 +376,11 @@ public void microsecond() { assertEquals(integerValue(0), eval(expression)); assertEquals("microsecond(TIME '01:02:03')", expression.toString()); + expression = dsl.microsecond(DSL.literal("01:02:03.12")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(120000), eval(expression)); + assertEquals("microsecond(\"01:02:03.12\")", expression.toString()); + expression = dsl.microsecond(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03.000010"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(10), expression.valueOf(env)); @@ -336,6 +391,11 @@ public void microsecond() { assertEquals(integerValue(123456), expression.valueOf(env)); assertEquals("microsecond(DATETIME '2020-08-17 01:02:03.123456')", expression.toString()); + expression = dsl.microsecond(DSL.literal("2020-08-17 01:02:03.123456")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(123456), expression.valueOf(env)); + assertEquals("microsecond(\"2020-08-17 01:02:03.123456\")", expression.toString()); + expression = dsl.microsecond(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03.000010"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(10), expression.valueOf(env)); @@ -354,6 +414,11 @@ public void minute() { assertEquals(integerValue(2), eval(expression)); assertEquals("minute(TIME '01:02:03')", expression.toString()); + expression = dsl.minute(DSL.literal("01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), eval(expression)); + assertEquals("minute(\"01:02:03\")", expression.toString()); + expression = dsl.minute(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(2), expression.valueOf(env)); @@ -363,6 +428,11 @@ public void minute() { assertEquals(INTEGER, expression.type()); assertEquals(integerValue(2), expression.valueOf(env)); assertEquals("minute(DATETIME '2020-08-17 01:02:03')", expression.toString()); + + expression = dsl.minute(DSL.literal("2020-08-17 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(2), expression.valueOf(env)); + assertEquals("minute(\"2020-08-17 01:02:03\")", expression.toString()); } @Test @@ -381,6 +451,11 @@ public void month() { assertEquals(INTEGER, expression.type()); assertEquals("month(\"2020-08-07\")", expression.toString()); assertEquals(integerValue(8), eval(expression)); + + expression = dsl.month(DSL.literal("2020-08-07 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals("month(\"2020-08-07 01:02:03\")", expression.toString()); + assertEquals(integerValue(8), eval(expression)); } @Test @@ -399,6 +474,11 @@ public void monthName() { assertEquals(STRING, expression.type()); assertEquals("monthname(\"2020-08-07\")", expression.toString()); assertEquals(stringValue("August"), eval(expression)); + + expression = dsl.monthname(DSL.literal("2020-08-07 01:02:03")); + assertEquals(STRING, expression.type()); + assertEquals("monthname(\"2020-08-07 01:02:03\")", expression.toString()); + assertEquals(stringValue("August"), eval(expression)); } @Test @@ -417,6 +497,11 @@ public void quarter() { assertEquals(INTEGER, expression.type()); assertEquals("quarter(\"2020-12-07\")", expression.toString()); assertEquals(integerValue(4), eval(expression)); + + expression = dsl.quarter(DSL.literal("2020-12-07 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals("quarter(\"2020-12-07 01:02:03\")", expression.toString()); + assertEquals(integerValue(4), eval(expression)); } @Test @@ -431,6 +516,16 @@ public void second() { assertEquals(integerValue(3), eval(expression)); assertEquals("second(TIME '01:02:03')", expression.toString()); + expression = dsl.second(DSL.literal("01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), eval(expression)); + assertEquals("second(\"01:02:03\")", expression.toString()); + + expression = dsl.second(DSL.literal("2020-08-17 01:02:03")); + assertEquals(INTEGER, expression.type()); + assertEquals(integerValue(3), eval(expression)); + assertEquals("second(\"2020-08-17 01:02:03\")", expression.toString()); + expression = dsl.second(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03"))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(3), expression.valueOf(env)); @@ -440,6 +535,11 @@ public void second() { assertEquals(INTEGER, expression.type()); assertEquals(integerValue(3), expression.valueOf(env)); assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); + + SemanticCheckException exception = + assertThrows(SemanticCheckException.class, () -> eval(dsl.second(DSL.literal("01:01:0C")))); + assertEquals("01:01:0C in unsupported format, please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", + exception.getMessage()); } @Test @@ -499,6 +599,11 @@ public void time_to_sec() { assertEquals(LONG, expression.type()); assertEquals("time_to_sec(TIME '22:23:00')", expression.toString()); assertEquals(longValue(80580L), eval(expression)); + + expression = dsl.time_to_sec(DSL.literal("22:23:00")); + assertEquals(LONG, expression.type()); + assertEquals("time_to_sec(\"22:23:00\")", expression.toString()); + assertEquals(longValue(80580L), eval(expression)); } @Test @@ -553,6 +658,11 @@ public void to_days() { assertEquals(LONG, expression.type()); assertEquals("to_days(\"1969-12-31\")", expression.toString()); assertEquals(longValue(719527L), eval(expression)); + + expression = dsl.to_days(DSL.literal("1969-12-31 01:01:01")); + assertEquals(LONG, expression.type()); + assertEquals("to_days(\"1969-12-31 01:01:01\")", expression.toString()); + assertEquals(longValue(719527L), eval(expression)); } @Test @@ -571,6 +681,11 @@ public void year() { assertEquals(INTEGER, expression.type()); assertEquals("year(\"2020-08-07\")", expression.toString()); assertEquals(integerValue(2020), eval(expression)); + + expression = dsl.year(DSL.literal("2020-08-07 01:01:01")); + assertEquals(INTEGER, expression.type()); + assertEquals("year(\"2020-08-07 01:01:01\")", expression.toString()); + assertEquals(integerValue(2020), eval(expression)); } private ExprValue eval(Expression expression) { diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 06e5c0dc1e..5adf62ef18 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -22,7 +22,7 @@ ABS Description ----------- -Specifications: +Specifications: 1. ABS(NUMBER T) -> T @@ -329,28 +329,27 @@ DATE_ADD Description ----------- -Usage: date_add(date, INTERVAL expr unit) adds the time interval expr to date +Usage: date_add(date, INTERVAL expr unit)/ date_add(date, expr) adds the time interval expr to date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG -Return type: +Return type map: -(DATE, DATE INTERVAL) -> DATE -(DATE, TIME INTERVAL) -> DATETIME -(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE, LONG -> DATE +DATETIME/TIMESTAMP, LONG -> DATETIME Synonyms: ADDDATE Example:: - od> SELECT DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR), DATE_ADD(DATE('2020-08-26'), 1) + od> SELECT DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR), DATE_ADD(DATE('2020-08-26'), 1), DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) fetched rows / total rows = 1/1 - +-------------------------------------------------+-----------------------------------+ - | DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR) | DATE_ADD(DATE('2020-08-26'), 1) | - |-------------------------------------------------+-----------------------------------| - | 2020-08-26 01:00:00 | 2020-08-27 | - +-------------------------------------------------+-----------------------------------+ - + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + | DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR) | DATE_ADD(DATE('2020-08-26'), 1) | DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |-------------------------------------------------+-----------------------------------+-------------------------------------------------| + | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 | + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ DATE_SUB ===== @@ -358,27 +357,28 @@ DATE_SUB Description ----------- -Usage: date_sub(date, INTERVAL expr unit) subtracts the time interval expr from date +Usage: date_sub(date, INTERVAL expr unit)/ date_sub(date, expr) subtracts the time interval expr from date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG -Return type: +Return type map: -(DATE, DATE INTERVAL) -> DATE -(DATE, TIME INTERVAL) -> DATETIME -(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE, LONG -> DATE +DATETIME/TIMESTAMP, LONG -> DATETIME Synonyms: SUBDATE Example:: - od> SELECT DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), DATE_SUB(DATE('2020-08-26'), 1) + od> SELECT DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), DATE_SUB(DATE('2020-08-26'), 1), DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) fetched rows / total rows = 1/1 - +-------------------------------------------------+-----------------------------------+ - | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | - |-------------------------------------------------+-----------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | - +-------------------------------------------------+-----------------------------------+ + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |-------------------------------------------------+-----------------------------------+-------------------------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | 2020-08-25 01:01:01 | + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + DAY ===== @@ -1243,27 +1243,28 @@ SUBDATE Description ----------- -Usage: subdate(date,INTERVAL expr unit) subtracts time interval from date. subdate(expr, days) subtracts interval in day unit from the temporal expression expr. +Usage: subdate(date, INTERVAL expr unit)/ subdate(date, expr) subtracts the time interval expr from date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL +Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG -Return type: +Return type map: -(DATE, DATE INTERVAL) -> DATE -(DATE, TIME INTERVAL) -> DATETIME -(DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE, LONG -> DATE +DATETIME/TIMESTAMP, LONG -> DATETIME Synonyms: DATE_SUB Example:: - od> SELECT SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), SUBDATE(DATE('2020-08-26'), 1) + od> SELECT SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), SUBDATE(DATE('2020-08-26'), 1), SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) fetched rows / total rows = 1/1 - +------------------------------------------------+----------------------------------+ - | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | - |------------------------------------------------+----------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | - +------------------------------------------------+----------------------------------+ + +------------------------------------------------+----------------------------------+------------------------------------------------+ + | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |------------------------------------------------+----------------------------------+------------------------------------------------| + | 2007-12-02 00:00:00 | 2020-08-25 | 2020-08-25 01:01:01 | + +------------------------------------------------+----------------------------------+------------------------------------------------+ + SUBSTRING ========= diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java new file mode 100644 index 0000000000..e3e2bf22fb --- /dev/null +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java @@ -0,0 +1,358 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.ppl; + +import static com.amazon.opendistroforelasticsearch.sql.legacy.TestsConstants.TEST_INDEX_DATE; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.rows; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.schema; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifySchema; +import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifySome; + +import java.io.IOException; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + +public class DateTimeFunctionIT extends PPLIntegTestCase { + + @Override + public void init() throws IOException { + loadIndex(Index.DATE); + } + + @Test + public void testDateAdd() throws IOException { + JSONObject result = + executeQuery(String.format( + "source=%s | eval f = date_add(timestamp('2020-09-16 17:30:00'), interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17 17:30:00")); + + result = executeQuery(String.format( + "source=%s | eval f = date_add(date('2020-09-16'), 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "date")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17")); + + result = executeQuery(String.format( + "source=%s | eval f = date_add('2020-09-16', 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17")); + + result = + executeQuery(String.format( + "source=%s | eval f = date_add('2020-09-16 17:30:00', interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17 17:30:00")); + } + + @Test + public void testDateSub() throws IOException { + JSONObject result = + executeQuery(String.format( + "source=%s | eval f = date_sub(timestamp('2020-09-16 17:30:00'), interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15 17:30:00")); + + result = executeQuery(String.format( + "source=%s | eval f = date_sub(date('2020-09-16'), 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "date")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15")); + + result = executeQuery(String.format( + "source=%s | eval f = date_sub('2020-09-16', 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15")); + + result = + executeQuery(String.format( + "source=%s | eval f = date_sub('2020-09-16 17:30:00', interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15 17:30:00")); + } + + @Test + public void testDay() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = day(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(16)); + + result = executeQuery(String.format( + "source=%s | eval f = day('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(16)); + } + + @Test + public void testDayName() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = dayname(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "string")); + verifySome(result.getJSONArray("datarows"), rows("Wednesday")); + + result = executeQuery(String.format( + "source=%s | eval f = dayname('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "string")); + verifySome(result.getJSONArray("datarows"), rows("Wednesday")); + } + + @Test + public void testDayOfMonth() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = dayofmonth(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(16)); + + result = executeQuery(String.format( + "source=%s | eval f = dayofmonth('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(16)); + } + + @Test + public void testDayOfWeek() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = dayofweek(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(4)); + + result = executeQuery(String.format( + "source=%s | eval f = dayofweek('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(4)); + } + + @Test + public void testDayOfYear() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = dayofyear(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(260)); + + result = executeQuery(String.format( + "source=%s | eval f = dayofyear('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(260)); + } + + @Test + public void testFromDays() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = from_days(738049) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "date")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-16")); + } + + @Test + public void testHour() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = hour(timestamp('2020-09-16 17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(17)); + + result = executeQuery(String.format( + "source=%s | eval f = hour(time('17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(17)); + + result = executeQuery(String.format( + "source=%s | eval f = hour('2020-09-16 17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(17)); + + result = executeQuery(String.format( + "source=%s | eval f = hour('17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(17)); + } + + @Test + public void testMicrosecond() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = microsecond(timestamp('2020-09-16 17:30:00.123456')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(123456)); + + result = executeQuery(String.format( + "source=%s | eval f = microsecond(time('17:30:00.000010')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(10)); + + result = executeQuery(String.format( + "source=%s | eval f = microsecond('2020-09-16 17:30:00.123456') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(123456)); + + result = executeQuery(String.format( + "source=%s | eval f = microsecond('17:30:00.000010') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(10)); + } + + @Test + public void testMinute() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = minute(timestamp('2020-09-16 17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(30)); + + result = executeQuery(String.format( + "source=%s | eval f = minute(time('17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(30)); + + result = executeQuery(String.format( + "source=%s | eval f = minute('2020-09-16 17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(30)); + + result = executeQuery(String.format( + "source=%s | eval f = minute('17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(30)); + } + + @Test + public void testMonth() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = month(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(9)); + + result = executeQuery(String.format( + "source=%s | eval f = month('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(9)); + } + + @Test + public void testMonthName() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = monthname(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "string")); + verifySome(result.getJSONArray("datarows"), rows("September")); + + result = executeQuery(String.format( + "source=%s | eval f = monthname('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "string")); + verifySome(result.getJSONArray("datarows"), rows("September")); + } + + @Test + public void testQuarter() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = quarter(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(3)); + + result = executeQuery(String.format( + "source=%s | eval f = quarter('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(3)); + } + + @Test + public void testSecond() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = second(timestamp('2020-09-16 17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(0)); + + result = executeQuery(String.format( + "source=%s | eval f = second(time('17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(0)); + + result = executeQuery(String.format( + "source=%s | eval f = second('2020-09-16 17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(0)); + + result = executeQuery(String.format( + "source=%s | eval f = second('17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(0)); + } + + @Test + public void testSubDate() throws IOException { + JSONObject result = + executeQuery(String.format( + "source=%s | eval f = subdate(timestamp('2020-09-16 17:30:00'), interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15 17:30:00")); + + result = executeQuery(String.format( + "source=%s | eval f = subdate(date('2020-09-16'), 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "date")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15")); + + result = + executeQuery(String.format( + "source=%s | eval f = subdate('2020-09-16 17:30:00', interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15 17:30:00")); + + result = executeQuery(String.format( + "source=%s | eval f = subdate('2020-09-16', 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-15")); + } + + @Test + public void testTimeToSec() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = time_to_sec(time('17:30:00')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "long")); + verifySome(result.getJSONArray("datarows"), rows(63000)); + + result = executeQuery(String.format( + "source=%s | eval f = time_to_sec('17:30:00') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "long")); + verifySome(result.getJSONArray("datarows"), rows(63000)); + } + + @Test + public void testToDays() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = to_days(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "long")); + verifySome(result.getJSONArray("datarows"), rows(738049)); + + result = executeQuery(String.format( + "source=%s | eval f = to_days('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "long")); + verifySome(result.getJSONArray("datarows"), rows(738049)); + } + + @Test + public void testYear() throws IOException { + JSONObject result = executeQuery(String.format( + "source=%s | eval f = year(date('2020-09-16')) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(2020)); + + result = executeQuery(String.format( + "source=%s | eval f = year('2020-09-16') | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "integer")); + verifySome(result.getJSONArray("datarows"), rows(2020)); + } +} diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java index 9e6953798e..f734283272 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -51,6 +51,16 @@ public void testDateAdd() throws IOException { result = executeQuery("select date_add(date('2020-09-16'), 1)"); verifySchema(result, schema("date_add(date('2020-09-16'), 1)", null, "date")); verifyDataRows(result, rows("2020-09-17")); + + result = executeQuery("select date_add('2020-09-16', 1)"); + verifySchema(result, schema("date_add('2020-09-16', 1)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17")); + + result = + executeQuery("select date_add('2020-09-16 17:30:00', interval 1 day)"); + verifySchema(result, + schema("date_add('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17 17:30:00")); } @Test @@ -64,6 +74,16 @@ public void testDateSub() throws IOException { result = executeQuery("select date_sub(date('2020-09-16'), 1)"); verifySchema(result, schema("date_sub(date('2020-09-16'), 1)", null, "date")); verifyDataRows(result, rows("2020-09-15")); + + result = executeQuery("select date_sub('2020-09-16', 1)"); + verifySchema(result, schema("date_sub('2020-09-16', 1)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15")); + + result = + executeQuery("select date_sub('2020-09-16 17:30:00', interval 1 day)"); + verifySchema(result, + schema("date_sub('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15 17:30:00")); } @Test @@ -71,6 +91,10 @@ public void testDay() throws IOException { JSONObject result = executeQuery("select day(date('2020-09-16'))"); verifySchema(result, schema("day(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(16)); + + result = executeQuery("select day('2020-09-16')"); + verifySchema(result, schema("day('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(16)); } @Test @@ -78,6 +102,10 @@ public void testDayName() throws IOException { JSONObject result = executeQuery("select dayname(date('2020-09-16'))"); verifySchema(result, schema("dayname(date('2020-09-16'))", null, "string")); verifyDataRows(result, rows("Wednesday")); + + result = executeQuery("select dayname('2020-09-16')"); + verifySchema(result, schema("dayname('2020-09-16')", null, "string")); + verifyDataRows(result, rows("Wednesday")); } @Test @@ -85,6 +113,10 @@ public void testDayOfMonth() throws IOException { JSONObject result = executeQuery("select dayofmonth(date('2020-09-16'))"); verifySchema(result, schema("dayofmonth(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(16)); + + result = executeQuery("select dayofmonth('2020-09-16')"); + verifySchema(result, schema("dayofmonth('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(16)); } @Test @@ -92,6 +124,10 @@ public void testDayOfWeek() throws IOException { JSONObject result = executeQuery("select dayofweek(date('2020-09-16'))"); verifySchema(result, schema("dayofweek(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(4)); + + result = executeQuery("select dayofweek('2020-09-16')"); + verifySchema(result, schema("dayofweek('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(4)); } @Test @@ -99,6 +135,10 @@ public void testDayOfYear() throws IOException { JSONObject result = executeQuery("select dayofyear(date('2020-09-16'))"); verifySchema(result, schema("dayofyear(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(260)); + + result = executeQuery("select dayofyear('2020-09-16')"); + verifySchema(result, schema("dayofyear('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(260)); } @Test @@ -117,6 +157,14 @@ public void testHour() throws IOException { result = executeQuery("select hour(time('17:30:00'))"); verifySchema(result, schema("hour(time('17:30:00'))", null, "integer")); verifyDataRows(result, rows(17)); + + result = executeQuery("select hour('2020-09-16 17:30:00')"); + verifySchema(result, schema("hour('2020-09-16 17:30:00')", null, "integer")); + verifyDataRows(result, rows(17)); + + result = executeQuery("select hour('17:30:00')"); + verifySchema(result, schema("hour('17:30:00')", null, "integer")); + verifyDataRows(result, rows(17)); } @Test @@ -128,6 +176,14 @@ public void testMicrosecond() throws IOException { result = executeQuery("select microsecond(time('17:30:00.000010'))"); verifySchema(result, schema("microsecond(time('17:30:00.000010'))", null, "integer")); verifyDataRows(result, rows(10)); + + result = executeQuery("select microsecond('2020-09-16 17:30:00.123456')"); + verifySchema(result, schema("microsecond('2020-09-16 17:30:00.123456')", null, "integer")); + verifyDataRows(result, rows(123456)); + + result = executeQuery("select microsecond('17:30:00.000010')"); + verifySchema(result, schema("microsecond('17:30:00.000010')", null, "integer")); + verifyDataRows(result, rows(10)); } @Test @@ -139,6 +195,14 @@ public void testMinute() throws IOException { result = executeQuery("select minute(time('17:30:00'))"); verifySchema(result, schema("minute(time('17:30:00'))", null, "integer")); verifyDataRows(result, rows(30)); + + result = executeQuery("select minute('2020-09-16 17:30:00')"); + verifySchema(result, schema("minute('2020-09-16 17:30:00')", null, "integer")); + verifyDataRows(result, rows(30)); + + result = executeQuery("select minute('17:30:00')"); + verifySchema(result, schema("minute('17:30:00')", null, "integer")); + verifyDataRows(result, rows(30)); } @Test @@ -146,6 +210,10 @@ public void testMonth() throws IOException { JSONObject result = executeQuery("select month(date('2020-09-16'))"); verifySchema(result, schema("month(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(9)); + + result = executeQuery("select month('2020-09-16')"); + verifySchema(result, schema("month('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(9)); } @Test @@ -153,6 +221,10 @@ public void testMonthName() throws IOException { JSONObject result = executeQuery("select monthname(date('2020-09-16'))"); verifySchema(result, schema("monthname(date('2020-09-16'))", null, "string")); verifyDataRows(result, rows("September")); + + result = executeQuery("select monthname('2020-09-16')"); + verifySchema(result, schema("monthname('2020-09-16')", null, "string")); + verifyDataRows(result, rows("September")); } @Test @@ -160,6 +232,10 @@ public void testQuarter() throws IOException { JSONObject result = executeQuery("select quarter(date('2020-09-16'))"); verifySchema(result, schema("quarter(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(3)); + + result = executeQuery("select quarter('2020-09-16')"); + verifySchema(result, schema("quarter('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(3)); } @Test @@ -171,6 +247,14 @@ public void testSecond() throws IOException { result = executeQuery("select second(time('17:30:00'))"); verifySchema(result, schema("second(time('17:30:00'))", null, "integer")); verifyDataRows(result, rows(0)); + + result = executeQuery("select second('2020-09-16 17:30:00')"); + verifySchema(result, schema("second('2020-09-16 17:30:00')", null, "integer")); + verifyDataRows(result, rows(0)); + + result = executeQuery("select second('17:30:00')"); + verifySchema(result, schema("second('17:30:00')", null, "integer")); + verifyDataRows(result, rows(0)); } @Test @@ -184,6 +268,16 @@ public void testSubDate() throws IOException { result = executeQuery("select subdate(date('2020-09-16'), 1)"); verifySchema(result, schema("subdate(date('2020-09-16'), 1)", null, "date")); verifyDataRows(result, rows("2020-09-15")); + + result = + executeQuery("select subdate('2020-09-16 17:30:00', interval 1 day)"); + verifySchema(result, + schema("subdate('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15 17:30:00")); + + result = executeQuery("select subdate('2020-09-16', 1)"); + verifySchema(result, schema("subdate('2020-09-16', 1)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15")); } @Test @@ -191,6 +285,10 @@ public void testTimeToSec() throws IOException { JSONObject result = executeQuery("select time_to_sec(time('17:30:00'))"); verifySchema(result, schema("time_to_sec(time('17:30:00'))", null, "long")); verifyDataRows(result, rows(63000)); + + result = executeQuery("select time_to_sec('17:30:00')"); + verifySchema(result, schema("time_to_sec('17:30:00')", null, "long")); + verifyDataRows(result, rows(63000)); } @Test @@ -198,6 +296,10 @@ public void testToDays() throws IOException { JSONObject result = executeQuery("select to_days(date('2020-09-16'))"); verifySchema(result, schema("to_days(date('2020-09-16'))", null, "long")); verifyDataRows(result, rows(738049)); + + result = executeQuery("select to_days('2020-09-16')"); + verifySchema(result, schema("to_days('2020-09-16')", null, "long")); + verifyDataRows(result, rows(738049)); } @Test @@ -205,6 +307,10 @@ public void testYear() throws IOException { JSONObject result = executeQuery("select year(date('2020-09-16'))"); verifySchema(result, schema("year(date('2020-09-16'))", null, "integer")); verifyDataRows(result, rows(2020)); + + result = executeQuery("select year('2020-09-16')"); + verifySchema(result, schema("year('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(2020)); } protected JSONObject executeQuery(String query) throws IOException { From 42c72226b41b5d1ed357509d40ddccec62eb3038 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 22 Sep 2020 18:33:47 -0700 Subject: [PATCH 36/42] fix doc format --- docs/user/dql/functions.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index c9acb01a21..c6959a7166 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -759,7 +759,9 @@ Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG Return type map: (DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + (DATE, LONG) -> DATE + (DATETIME/TIMESTAMP, LONG) -> DATETIME Synonyms: `DATE_ADD`_ @@ -833,7 +835,9 @@ Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG Return type map: DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME + DATE, LONG -> DATE + DATETIME/TIMESTAMP, LONG -> DATETIME Synonyms: `ADDDATE`_ @@ -862,10 +866,12 @@ Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG Return type map: DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME + DATE, LONG -> DATE + DATETIME/TIMESTAMP, LONG -> DATETIME -Synonyms: SUBDATE +Synonyms: `SUBDATE`_ Example:: @@ -1217,10 +1223,12 @@ Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG Return type map: DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME + DATE, LONG -> DATE + DATETIME/TIMESTAMP, LONG -> DATETIME -Synonyms: DATE_SUB +Synonyms: `DATE_SUB`_ Example:: From 0f3894a92e85604413bda629a7edca8325099769 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Tue, 22 Sep 2020 19:14:53 -0700 Subject: [PATCH 37/42] update tests for adddate --- .../expression/datetime/DateTimeFunction.java | 10 ++++--- .../datetime/DateTimeFunctionTest.java | 16 +++++++++++ docs/user/dql/functions.rst | 14 +++++----- .../sql/ppl/DateTimeFunctionIT.java | 27 +++++++++++++++++++ .../sql/sql/DateTimeFunctionIT.java | 13 ++++++++- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 916da93833..60d2feaf3c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -96,13 +96,14 @@ public void register(BuiltinFunctionRepository repository) { /** * Specify a start date and add a temporal amount to the date. * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (DATE, DATETIME/TIMESTAMP, INTERVAL) -> DATETIME + * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME * (DATE, LONG) -> DATE - * (DATETIME/TIMESTAMP, LONG) -> DATETIME + * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ private FunctionResolver adddate() { return define(BuiltinFunctionName.ADDDATE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATE, DATE, INTERVAL), + impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), + DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATETIME, INTERVAL), @@ -110,7 +111,8 @@ private FunctionResolver adddate() { DATETIME, TIMESTAMP, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATE, DATE, LONG), impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG) + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG), + impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, STRING, LONG) ); } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 45607690f1..5d10960c39 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -88,6 +88,22 @@ public void adddate() { assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); assertEquals("adddate(date(\"2020-08-26\"), interval(1, \"hour\"))", expr.toString()); + expr = dsl.adddate(DSL.literal("2020-08-26"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDateValue("2020-09-02"), expr.valueOf(env)); + assertEquals("adddate(\"2020-08-26\", 7)", expr.toString()); + + expr = dsl.adddate(DSL.literal("2020-08-26 12:05:00"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-09-02 12:05:00"), expr.valueOf(env)); + assertEquals("adddate(\"2020-08-26 12:05:00\", 7)", expr.toString()); + + expr = dsl + .adddate(DSL.literal("2020-08-26"), dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); + assertEquals("adddate(\"2020-08-26\", interval(1, \"hour\"))", expr.toString()); + when(nullRef.type()).thenReturn(DATE); assertEquals(nullValue(), eval(dsl.adddate(nullRef, DSL.literal(1L)))); assertEquals(nullValue(), diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index c6959a7166..d309e7e88e 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -752,7 +752,7 @@ ADDDATE Description >>>>>>>>>>> -Usage: adddate(date, INTERVAL expr unit) adds the time interval of second argument to date; adddate(date, days) adds the second argument as integer number of days to date. +Usage: adddate(date, INTERVAL expr unit)/ adddate(date, expr) adds the time interval of second argument to date; adddate(date, days) adds the second argument as integer number of days to date. Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG @@ -768,13 +768,13 @@ Synonyms: `DATE_ADD`_ Example:: - >od SELECT ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR), ADDDATE(DATE('2020-08-26'), 1) + od> SELECT ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR), ADDDATE(DATE('2020-08-26'), 1), ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) fetched rows / total rows = 1/1 - +------------------------------------------------+----------------------------------+ - | ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR) | ADDDATE(DATE('2020-08-26'), 1) | - |------------------------------------------------+----------------------------------| - | DATETIME '2020-08-26 01:00:00' | DATE '2020-08-26' | - +------------------------------------------------+----------------------------------+ + +------------------------------------------------+----------------------------------+------------------------------------------------+ + | ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR) | ADDDATE(DATE('2020-08-26'), 1) | ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |------------------------------------------------+----------------------------------+------------------------------------------------| + | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 | + +------------------------------------------------+----------------------------------+------------------------------------------------+ CURDATE diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java index e3e2bf22fb..bcac70a94f 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DateTimeFunctionIT.java @@ -32,6 +32,33 @@ public void init() throws IOException { loadIndex(Index.DATE); } + @Test + public void testAddDate() throws IOException { + JSONObject result = + executeQuery(String.format( + "source=%s | eval f = adddate(timestamp('2020-09-16 17:30:00'), interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17 17:30:00")); + + result = executeQuery(String.format( + "source=%s | eval f = adddate(date('2020-09-16'), 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "date")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17")); + + result = executeQuery(String.format( + "source=%s | eval f = adddate('2020-09-16', 1) | fields f", TEST_INDEX_DATE)); + verifySchema(result, schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17")); + + result = + executeQuery(String.format( + "source=%s | eval f = adddate('2020-09-16 17:30:00', interval 1 day) | fields f", TEST_INDEX_DATE)); + verifySchema(result, + schema("f", null, "datetime")); + verifySome(result.getJSONArray("datarows"), rows("2020-09-17 17:30:00")); + } + @Test public void testDateAdd() throws IOException { JSONObject result = diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java index 3ab9622f65..46dfdf2905 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -51,6 +51,16 @@ public void testAddDate() throws IOException { result = executeQuery("select adddate(date('2020-09-16'), 1)"); verifySchema(result, schema("adddate(date('2020-09-16'), 1)", null, "date")); verifyDataRows(result, rows("2020-09-17")); + + result = executeQuery("select adddate('2020-09-16', 1)"); + verifySchema(result, schema("adddate('2020-09-16', 1)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17")); + + result = + executeQuery("select adddate('2020-09-16 17:30:00', interval 1 day)"); + verifySchema(result, + schema("adddate('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17 17:30:00")); } @Test @@ -183,7 +193,8 @@ public void testHour() throws IOException { @Test public void testMicrosecond() throws IOException { JSONObject result = executeQuery("select microsecond(timestamp('2020-09-16 17:30:00.123456'))"); - verifySchema(result, schema("microsecond(timestamp('2020-09-16 17:30:00.123456'))", null, "integer")); + verifySchema(result, + schema("microsecond(timestamp('2020-09-16 17:30:00.123456'))", null, "integer")); verifyDataRows(result, rows(123456)); result = executeQuery("select microsecond(time('17:30:00.000010'))"); From a73a8e9975476eb198bcb87f516edc20ee7abddc Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Wed, 23 Sep 2020 18:21:16 -0700 Subject: [PATCH 38/42] move string conversion to ExprStringValue --- .../sql/data/model/ExprStringValue.java | 39 ++++ .../expression/datetime/DateTimeFunction.java | 216 ++++-------------- .../datetime/DateTimeFunctionTest.java | 37 ++- docs/user/dql/functions.rst | 4 +- .../sql/sql/DateTimeFunctionIT.java | 32 ++- 5 files changed, 137 insertions(+), 191 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java index 8ea3e0f60d..1c0fdf982e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java @@ -17,6 +17,11 @@ import com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType; import com.amazon.opendistroforelasticsearch.sql.data.type.ExprType; +import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeParseException; import java.util.Objects; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; @@ -43,6 +48,40 @@ public String stringValue() { return value; } + @Override + public LocalDateTime datetimeValue() { + ExprValue date; + try { + date = new ExprDatetimeValue(value); + } catch (SemanticCheckException e) { + date = new ExprDateValue(value); + date = new ExprDatetimeValue(LocalDateTime.of(date.dateValue(), LocalTime.of(0, 0, 0))); + } + return date.datetimeValue(); + } + + @Override + public LocalDate dateValue() { + ExprValue date; + try { + date = new ExprDatetimeValue(value); + } catch (SemanticCheckException e) { + date = new ExprDateValue(value); + } + return date.dateValue(); + } + + @Override + public LocalTime timeValue() { + ExprValue date; + try { + date = new ExprDatetimeValue(value); + } catch (SemanticCheckException e) { + date = new ExprTimeValue(value); + } + return date.timeValue(); + } + @Override public String toString() { return String.format("\"%s\"", value); diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java index 60d2feaf3c..bddf583530 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunction.java @@ -37,15 +37,11 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; -import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; +import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.time.format.TextStyle; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -100,8 +96,9 @@ public void register(BuiltinFunctionRepository repository) { * (DATE, LONG) -> DATE * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ - private FunctionResolver adddate() { - return define(BuiltinFunctionName.ADDDATE.getName(), + + private FunctionResolver add_date(FunctionName functionName) { + return define(functionName, impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL), @@ -116,6 +113,10 @@ private FunctionResolver adddate() { ); } + private FunctionResolver adddate() { + return add_date(BuiltinFunctionName.ADDDATE.getName()); + } + /** * Extracts the date part of a date and time value. * Also to construct a date type. The supported signatures: @@ -129,27 +130,8 @@ private FunctionResolver date() { impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP)); } - /** - * Specify a start date and add a temporal amount to the date. - * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME - * (DATE, LONG) -> DATE - * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME - */ private FunctionResolver date_add() { - return define(BuiltinFunctionName.DATE_ADD.getName(), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), - DATETIME, STRING, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), - DATETIME, DATETIME, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), - DATETIME, TIMESTAMP, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATE, DATE, LONG), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG), - impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, STRING, LONG) - ); + return add_date(BuiltinFunctionName.DATE_ADD.getName()); } /** @@ -159,8 +141,8 @@ private FunctionResolver date_add() { * (DATE, LONG) -> DATE * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME */ - private FunctionResolver date_sub() { - return define(BuiltinFunctionName.DATE_SUB.getName(), + private FunctionResolver sub_date(FunctionName functionName) { + return define(functionName, impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, STRING, INTERVAL), impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), @@ -175,6 +157,10 @@ private FunctionResolver date_sub() { ); } + private FunctionResolver date_sub() { + return sub_date(BuiltinFunctionName.DATE_SUB.getName()); + } + /** * DAY(STRING/DATE/DATETIME/TIMESTAMP). return the day of the month (1-31). */ @@ -331,27 +317,8 @@ private FunctionResolver second() { ); } - /** - * Specify a start date and subtract a temporal amount to the date. - * The return type depends on the date type and the interval unit. Detailed supported signatures: - * (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME - * (DATE, LONG) -> DATE - * (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME - */ private FunctionResolver subdate() { - return define(BuiltinFunctionName.SUBDATE.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), - DATETIME, STRING, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), DATETIME, DATE, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), - DATETIME, DATETIME, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateInterval), - DATETIME, TIMESTAMP, INTERVAL), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATE, DATE, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, DATETIME, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, TIMESTAMP, LONG), - impl(nullMissingHandling(DateTimeFunction::exprSubDateDays), DATETIME, STRING, LONG) - ); + return sub_date(BuiltinFunctionName.SUBDATE.getName()); } /** @@ -424,9 +391,9 @@ private FunctionResolver year() { * @return Datetime resulted from expr added to date. */ private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprDatetimeValue(exprValue.datetimeValue().plus(expr.intervalValue())); + ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().plus(expr.intervalValue())); + return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue()) + : exprValue); } /** @@ -437,12 +404,9 @@ private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) { * @return Date/Datetime resulted from days added to date. */ private ExprValue exprAddDateDays(ExprValue date, ExprValue days) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - if (exprValue instanceof ExprDateValue) { - return new ExprDateValue(exprValue.dateValue().plusDays(days.longValue())); - } - return new ExprDatetimeValue(exprValue.datetimeValue().plusDays(days.longValue())); + ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().plusDays(days.longValue())); + return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue()) + : exprValue); } /** @@ -466,10 +430,8 @@ private ExprValue exprDate(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprDayName(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; return new ExprStringValue( - exprValue.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); + date.dateValue().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); } /** @@ -479,9 +441,7 @@ private ExprValue exprDayName(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfMonth(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprIntegerValue(exprValue.dateValue().getDayOfMonth()); + return new ExprIntegerValue(date.dateValue().getDayOfMonth()); } /** @@ -491,9 +451,7 @@ private ExprValue exprDayOfMonth(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfWeek(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprIntegerValue((exprValue.dateValue().getDayOfWeek().getValue() % 7) + 1); + return new ExprIntegerValue((date.dateValue().getDayOfWeek().getValue() % 7) + 1); } /** @@ -503,9 +461,7 @@ private ExprValue exprDayOfWeek(ExprValue date) { * @return ExprValue. */ private ExprValue exprDayOfYear(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprIntegerValue(exprValue.dateValue().getDayOfYear()); + return new ExprIntegerValue(date.dateValue().getDayOfYear()); } /** @@ -525,9 +481,7 @@ private ExprValue exprFromDays(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprHour(ExprValue time) { - ExprValue exprValue = - time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; - return new ExprIntegerValue(exprValue.timeValue().getHour()); + return new ExprIntegerValue(time.timeValue().getHour()); } /** @@ -537,10 +491,8 @@ private ExprValue exprHour(ExprValue time) { * @return ExprValue. */ private ExprValue exprMicrosecond(ExprValue time) { - ExprValue exprValue = - time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; return new ExprIntegerValue( - TimeUnit.MICROSECONDS.convert(exprValue.timeValue().getNano(), TimeUnit.NANOSECONDS)); + TimeUnit.MICROSECONDS.convert(time.timeValue().getNano(), TimeUnit.NANOSECONDS)); } /** @@ -550,9 +502,7 @@ private ExprValue exprMicrosecond(ExprValue time) { * @return ExprValue. */ private ExprValue exprMinute(ExprValue time) { - ExprValue exprValue = - time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; - return new ExprIntegerValue(exprValue.timeValue().getMinute()); + return new ExprIntegerValue(time.timeValue().getMinute()); } /** @@ -562,9 +512,7 @@ private ExprValue exprMinute(ExprValue time) { * @return ExprValue. */ private ExprValue exprMonth(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprIntegerValue(exprValue.dateValue().getMonthValue()); + return new ExprIntegerValue(date.dateValue().getMonthValue()); } /** @@ -574,10 +522,8 @@ private ExprValue exprMonth(ExprValue date) { * @return ExprValue. */ private ExprValue exprMonthName(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; return new ExprStringValue( - exprValue.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); + date.dateValue().getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault())); } /** @@ -587,9 +533,7 @@ private ExprValue exprMonthName(ExprValue date) { * @return ExprValue. */ private ExprValue exprQuarter(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - int month = exprValue.dateValue().getMonthValue(); + int month = date.dateValue().getMonthValue(); return new ExprIntegerValue((month / 3) + ((month % 3) == 0 ? 0 : 1)); } @@ -600,9 +544,7 @@ private ExprValue exprQuarter(ExprValue date) { * @return ExprValue. */ private ExprValue exprSecond(ExprValue time) { - ExprValue exprValue = - time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; - return new ExprIntegerValue(exprValue.timeValue().getSecond()); + return new ExprIntegerValue(time.timeValue().getSecond()); } /** @@ -613,13 +555,9 @@ private ExprValue exprSecond(ExprValue time) { * @return Date/Datetime resulted from days subtracted to date. */ private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - if (exprValue instanceof ExprDateValue) { - return new ExprDateValue(exprValue.dateValue().minusDays(days.longValue())); - } else { - return new ExprDatetimeValue(exprValue.datetimeValue().minusDays(days.longValue())); - } + ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().minusDays(days.longValue())); + return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue()) + : exprValue); } /** @@ -630,9 +568,9 @@ private ExprValue exprSubDateDays(ExprValue date, ExprValue days) { * @return Datetime resulted from expr subtracted to date. */ private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprDatetimeValue(exprValue.datetimeValue().minus(expr.intervalValue())); + ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().minus(expr.intervalValue())); + return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue()) + : exprValue); } /** @@ -670,9 +608,7 @@ private ExprValue exprTimestamp(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprTimeToSec(ExprValue time) { - ExprValue exprValue = - time instanceof ExprStringValue ? getStringValue(time.stringValue()) : time; - return new ExprLongValue(exprValue.timeValue().toSecondOfDay()); + return new ExprLongValue(time.timeValue().toSecondOfDay()); } /** @@ -682,9 +618,7 @@ private ExprValue exprTimeToSec(ExprValue time) { * @return ExprValue. */ private ExprValue exprToDays(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprLongValue(exprValue.dateValue().toEpochDay() + DAYS_0000_TO_1970); + return new ExprLongValue(date.dateValue().toEpochDay() + DAYS_0000_TO_1970); } /** @@ -694,73 +628,7 @@ private ExprValue exprToDays(ExprValue date) { * @return ExprValue. */ private ExprValue exprYear(ExprValue date) { - ExprValue exprValue = - date instanceof ExprStringValue ? getStringValue(date.stringValue()) : date; - return new ExprIntegerValue(exprValue.dateValue().getYear()); - } - - /** - * Returns date, time or datetime for string value. - * - * @param string ExprValue of String type. - * @return ExprValue. - */ - private ExprValue getStringValue(String string) { - if (isValidDateTime(string)) { - return new ExprDatetimeValue(string); - } else if (isValidDate(string)) { - return new ExprDateValue(string); - } else if (isValidTime(string)) { - return new ExprTimeValue(string); - } - throw new SemanticCheckException(String.format("%s in unsupported format, please " - + "use yyyy-MM-dd HH:mm:ss[.SSSSSS]", string)); - } - - /** - * Returns true if string is in datetime format. - * - * @param datetime ExprValue of String type. - * @return ExprValue. - */ - private boolean isValidDateTime(String datetime) { - final DateTimeFormatter formatter = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss[.SSSSSS]"); - try { - LocalDateTime.parse(datetime, formatter); - return true; - } catch (DateTimeParseException e) { - return false; - } + return new ExprIntegerValue(date.dateValue().getYear()); } - /** - * Returns true if string is in date format. - * - * @param date ExprValue of String type. - * @return ExprValue. - */ - private boolean isValidDate(String date) { - try { - LocalDate.parse(date); - return true; - } catch (DateTimeParseException e) { - return false; - } - } - - /** - * Returns true if string is in time format. - * - * @param time ExprValue of String type. - * @return ExprValue. - */ - private boolean isValidTime(String time) { - try { - LocalTime.parse(time); - return true; - } catch (DateTimeParseException e) { - return false; - } - } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java index 5d10960c39..3d60a256b5 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -31,7 +31,6 @@ import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIME; import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.TIMESTAMP; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprDateValue; @@ -40,7 +39,6 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimeValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTimestampValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; -import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.ExpressionTestBase; @@ -104,6 +102,12 @@ public void adddate() { assertEquals(new ExprDatetimeValue("2020-08-26 01:00:00"), expr.valueOf(env)); assertEquals("adddate(\"2020-08-26\", interval(1, \"hour\"))", expr.toString()); + expr = dsl + .adddate(DSL.literal("2020-08-26"), dsl.interval(DSL.literal(1), DSL.literal("day"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDateValue("2020-08-27"), expr.valueOf(env)); + assertEquals("adddate(\"2020-08-26\", interval(1, \"day\"))", expr.toString()); + when(nullRef.type()).thenReturn(DATE); assertEquals(nullValue(), eval(dsl.adddate(nullRef, DSL.literal(1L)))); assertEquals(nullValue(), @@ -596,11 +600,6 @@ public void second() { assertEquals(INTEGER, expression.type()); assertEquals(integerValue(3), expression.valueOf(env)); assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); - - SemanticCheckException exception = - assertThrows(SemanticCheckException.class, () -> eval(dsl.second(DSL.literal("01:01:0C")))); - assertEquals("01:01:0C in unsupported format, please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", - exception.getMessage()); } @Test @@ -610,11 +609,21 @@ public void subdate() { assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); assertEquals("subdate(date(\"2020-08-26\"), 7)", expr.toString()); + expr = dsl.subdate(DSL.literal("2020-08-26"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDateValue("2020-08-19"), expr.valueOf(env)); + assertEquals("subdate(\"2020-08-26\", 7)", expr.toString()); + expr = dsl.subdate(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), DSL.literal(7)); assertEquals(DATETIME, expr.type()); assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); assertEquals("subdate(timestamp(\"2020-08-26 12:05:00\"), 7)", expr.toString()); + expr = dsl.subdate(DSL.literal("2020-08-26 12:05:00"), DSL.literal(7)); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-19 12:05:00"), expr.valueOf(env)); + assertEquals("subdate(\"2020-08-26 12:05:00\", 7)", expr.toString()); + expr = dsl.subdate(dsl.timestamp(DSL.literal("2020-08-26 12:05:00")), dsl.interval(DSL.literal(1), DSL.literal("hour"))); assertEquals(DATETIME, expr.type()); @@ -622,6 +631,20 @@ public void subdate() { assertEquals("subdate(timestamp(\"2020-08-26 12:05:00\"), interval(1, \"hour\"))", expr.toString()); + expr = dsl.subdate(DSL.literal("2020-08-26 12:05:00"), + dsl.interval(DSL.literal(1), DSL.literal("hour"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDatetimeValue("2020-08-26 11:05:00"), expr.valueOf(env)); + assertEquals("subdate(\"2020-08-26 12:05:00\", interval(1, \"hour\"))", + expr.toString()); + + expr = dsl.subdate(DSL.literal("2020-08-26"), + dsl.interval(DSL.literal(1), DSL.literal("day"))); + assertEquals(DATETIME, expr.type()); + assertEquals(new ExprDateValue("2020-08-25"), expr.valueOf(env)); + assertEquals("subdate(\"2020-08-26\", interval(1, \"day\"))", + expr.toString()); + when(nullRef.type()).thenReturn(DATE); assertEquals(nullValue(), eval(dsl.subdate(nullRef, DSL.literal(1L)))); assertEquals(nullValue(), diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index d309e7e88e..8aee59e1d7 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -880,7 +880,7 @@ Example:: +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) | |-------------------------------------------------+-----------------------------------+-------------------------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | 2020-08-25 01:01:01 | + | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 | +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ @@ -1237,7 +1237,7 @@ Example:: +------------------------------------------------+----------------------------------+------------------------------------------------+ | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | |------------------------------------------------+----------------------------------+------------------------------------------------| - | 2007-12-02 00:00:00 | 2020-08-25 | 2020-08-25 01:01:01 | + | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 | +------------------------------------------------+----------------------------------+------------------------------------------------+ diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java index 46dfdf2905..9d90ffec02 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/sql/DateTimeFunctionIT.java @@ -56,11 +56,15 @@ public void testAddDate() throws IOException { verifySchema(result, schema("adddate('2020-09-16', 1)", null, "datetime")); verifyDataRows(result, rows("2020-09-17")); - result = - executeQuery("select adddate('2020-09-16 17:30:00', interval 1 day)"); + result = executeQuery("select adddate('2020-09-16 17:30:00', interval 1 day)"); verifySchema(result, schema("adddate('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); verifyDataRows(result, rows("2020-09-17 17:30:00")); + + result = executeQuery("select adddate('2020-09-16', interval 1 day)"); + verifySchema(result, + schema("adddate('2020-09-16', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17")); } @Test @@ -79,11 +83,15 @@ public void testDateAdd() throws IOException { verifySchema(result, schema("date_add('2020-09-16', 1)", null, "datetime")); verifyDataRows(result, rows("2020-09-17")); - result = - executeQuery("select date_add('2020-09-16 17:30:00', interval 1 day)"); + result = executeQuery("select date_add('2020-09-16 17:30:00', interval 1 day)"); verifySchema(result, schema("date_add('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); verifyDataRows(result, rows("2020-09-17 17:30:00")); + + result = executeQuery("select date_add('2020-09-16', interval 1 day)"); + verifySchema(result, + schema("date_add('2020-09-16', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-17")); } @Test @@ -102,11 +110,15 @@ public void testDateSub() throws IOException { verifySchema(result, schema("date_sub('2020-09-16', 1)", null, "datetime")); verifyDataRows(result, rows("2020-09-15")); - result = - executeQuery("select date_sub('2020-09-16 17:30:00', interval 1 day)"); + result = executeQuery("select date_sub('2020-09-16 17:30:00', interval 1 day)"); verifySchema(result, schema("date_sub('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); verifyDataRows(result, rows("2020-09-15 17:30:00")); + + result = executeQuery("select date_sub('2020-09-16', interval 1 day)"); + verifySchema(result, + schema("date_sub('2020-09-16', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15")); } @Test @@ -293,8 +305,7 @@ public void testSubDate() throws IOException { verifySchema(result, schema("subdate(date('2020-09-16'), 1)", null, "date")); verifyDataRows(result, rows("2020-09-15")); - result = - executeQuery("select subdate('2020-09-16 17:30:00', interval 1 day)"); + result = executeQuery("select subdate('2020-09-16 17:30:00', interval 1 day)"); verifySchema(result, schema("subdate('2020-09-16 17:30:00', interval 1 day)", null, "datetime")); verifyDataRows(result, rows("2020-09-15 17:30:00")); @@ -302,6 +313,11 @@ public void testSubDate() throws IOException { result = executeQuery("select subdate('2020-09-16', 1)"); verifySchema(result, schema("subdate('2020-09-16', 1)", null, "datetime")); verifyDataRows(result, rows("2020-09-15")); + + result = executeQuery("select subdate('2020-09-16', interval 1 day)"); + verifySchema(result, + schema("subdate('2020-09-16', interval 1 day)", null, "datetime")); + verifyDataRows(result, rows("2020-09-15")); } @Test From ea9b19088bdad36d4f8d6f7c71a1171bf202cafa Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Thu, 24 Sep 2020 10:58:59 -0700 Subject: [PATCH 39/42] add string type in doc --- docs/user/dql/functions.rst | 54 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 8aee59e1d7..33c20137f5 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -754,15 +754,15 @@ Description Usage: adddate(date, INTERVAL expr unit)/ adddate(date, expr) adds the time interval of second argument to date; adddate(date, days) adds the second argument as integer number of days to date. -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG +Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG Return type map: -(DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME +(DATE/DATETIME/TIMESTAMP/STRING, INTERVAL) -> DATETIME (DATE, LONG) -> DATE -(DATETIME/TIMESTAMP, LONG) -> DATETIME +(DATETIME/TIMESTAMP/STRING, LONG) -> DATETIME Synonyms: `DATE_ADD`_ @@ -830,15 +830,15 @@ Description Usage: date_add(date, INTERVAL expr unit)/ date_add(date, expr) adds the time interval expr to date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG +Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG Return type map: -DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME DATE, LONG -> DATE -DATETIME/TIMESTAMP, LONG -> DATETIME +DATETIME/TIMESTAMP/STRING, LONG -> DATETIME Synonyms: `ADDDATE`_ @@ -861,15 +861,15 @@ Description Usage: date_sub(date, INTERVAL expr unit)/ date_sub(date, expr) subtracts the time interval expr from date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG +Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG Return type map: -DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME DATE, LONG -> DATE -DATETIME/TIMESTAMP, LONG -> DATETIME +DATETIME/TIMESTAMP/STRING, LONG -> DATETIME Synonyms: `SUBDATE`_ @@ -892,7 +892,7 @@ Description Usage: day(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -917,7 +917,7 @@ Description Usage: dayname(date) returns the name of the weekday for date, including Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: STRING @@ -940,7 +940,7 @@ Description Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -965,7 +965,7 @@ Description Usage: dayofweek(date) returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -989,7 +989,7 @@ Description Usage: dayofyear(date) returns the day of the year for date, in the range 1 to 366. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -1035,7 +1035,7 @@ Description Usage: hour(time) extracts the hour value for time. Different from the time of day value, the time value has a large range and can be greater than 23, so the return value of hour(time) can be also greater than 23. -Argument type: TIME +Argument type: STRING/TIME/DATETIME/TIMESTAMP Return type: INTEGER @@ -1069,7 +1069,7 @@ Description Usage: microsecond(expr) returns the microseconds from the time or datetime expression expr as a number in the range from 0 to 999999. -Argument type: TIME +Argument type: STRING/TIME/DATETIME/TIMESTAMP Return type: INTEGER @@ -1092,7 +1092,7 @@ Description Usage: minute(time) returns the minute for time, in the range 0 to 59. -Argument type: TIME +Argument type: STRING/TIME/DATETIME/TIMESTAMP Return type: INTEGER @@ -1115,7 +1115,7 @@ Description Usage: month(date) returns the month for date, in the range 1 to 12 for January to December. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -1138,7 +1138,7 @@ Description Usage: monthname(date) returns the full name of the month for date. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: STRING @@ -1172,7 +1172,7 @@ Description Usage: quarter(date) returns the quarter of the year for date, in the range 1 to 4. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER @@ -1195,7 +1195,7 @@ Description Usage: second(time) returns the second for time, in the range 0 to 59. -Argument type: TIME +Argument type: STRING/TIME/DATETIME/TIMESTAMP Return type: INTEGER @@ -1218,15 +1218,15 @@ Description Usage: subdate(date, INTERVAL expr unit)/ subdate(date, expr) subtracts the time interval expr from date -Argument type: DATE/DATETIME/TIMESTAMP, INTERVAL/LONG +Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG Return type map: -DATE/DATETIME/TIMESTAMP, INTERVAL -> DATETIME +DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME DATE, LONG -> DATE -DATETIME/TIMESTAMP, LONG -> DATETIME +DATETIME/TIMESTAMP/STRING, LONG -> DATETIME Synonyms: `DATE_SUB`_ @@ -1272,7 +1272,7 @@ Description Usage: time_to_sec(time) returns the time argument, converted to seconds. -Argument type: TIME +Argument type: STRING/TIME/DATETIME/TIMESTAMP Return type: LONG @@ -1318,7 +1318,7 @@ Description Usage: to_days(date) returns the day number (the number of days since year 0) of the given date. Returns NULL if date is invalid. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: LONG @@ -1342,7 +1342,7 @@ Description Usage: year(date) returns the year for date, in the range 1000 to 9999, or 0 for the “zero” date. -Argument type: DATE +Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER From dc70cd6986eca3ca66268a6bb66c4b4d44505464 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Mon, 28 Sep 2020 11:15:06 -0700 Subject: [PATCH 40/42] add test cases for datetime function in ExpeStringValue --- .../sql/data/model/ExprStringValue.java | 26 +++++----- .../sql/data/model/DateTimeValueTest.java | 47 +++++++++++++++++++ 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java index 1c0fdf982e..42de804fe3 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java @@ -50,36 +50,36 @@ public String stringValue() { @Override public LocalDateTime datetimeValue() { - ExprValue date; try { - date = new ExprDatetimeValue(value); + return new ExprDatetimeValue(value).datetimeValue(); } catch (SemanticCheckException e) { - date = new ExprDateValue(value); - date = new ExprDatetimeValue(LocalDateTime.of(date.dateValue(), LocalTime.of(0, 0, 0))); + try { + return new ExprDatetimeValue( + LocalDateTime.of(new ExprDateValue(value).dateValue(), LocalTime.of(0, 0, 0))) + .datetimeValue(); + } catch (SemanticCheckException exception) { + throw new SemanticCheckException(String.format("datetime:%s in unsupported format, please " + + "use yyyy-MM-dd HH:mm:ss[.SSSSSS]", value)); + } } - return date.datetimeValue(); } @Override public LocalDate dateValue() { - ExprValue date; try { - date = new ExprDatetimeValue(value); + return new ExprDatetimeValue(value).dateValue(); } catch (SemanticCheckException e) { - date = new ExprDateValue(value); + return new ExprDateValue(value).dateValue(); } - return date.dateValue(); } @Override public LocalTime timeValue() { - ExprValue date; try { - date = new ExprDatetimeValue(value); + return new ExprDatetimeValue(value).timeValue(); } catch (SemanticCheckException e) { - date = new ExprTimeValue(value); + return new ExprTimeValue(value).timeValue(); } - return date.timeValue(); } @Override diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java index cb07d9ae32..410ea77453 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/DateTimeValueTest.java @@ -128,4 +128,51 @@ public void datetimeInUnsupportedFormat() { + "please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", exception.getMessage()); } + + @Test + public void stringDateTimeValue() { + ExprValue stringValue = new ExprStringValue("2020-08-17 19:44:00"); + + assertEquals(LocalDateTime.parse("2020-08-17T19:44:00"), stringValue.datetimeValue()); + assertEquals(LocalDate.parse("2020-08-17"), stringValue.dateValue()); + assertEquals(LocalTime.parse("19:44:00"), stringValue.timeValue()); + assertEquals("\"2020-08-17 19:44:00\"", stringValue.toString()); + + SemanticCheckException exception = + assertThrows(SemanticCheckException.class, + () -> new ExprStringValue("2020-07-07T01:01:01Z").datetimeValue()); + assertEquals( + "datetime:2020-07-07T01:01:01Z in unsupported format, " + + "please use yyyy-MM-dd HH:mm:ss[.SSSSSS]", + exception.getMessage()); + } + + @Test + public void stringDateValue() { + ExprValue stringValue = new ExprStringValue("2020-08-17"); + + assertEquals(LocalDateTime.parse("2020-08-17T00:00:00"), stringValue.datetimeValue()); + assertEquals(LocalDate.parse("2020-08-17"), stringValue.dateValue()); + assertEquals("\"2020-08-17\"", stringValue.toString()); + + SemanticCheckException exception = + assertThrows(SemanticCheckException.class, + () -> new ExprStringValue("2020-07-07Z").dateValue()); + assertEquals("date:2020-07-07Z in unsupported format, please use yyyy-MM-dd", + exception.getMessage()); + } + + @Test + public void stringTimeValue() { + ExprValue stringValue = new ExprStringValue("19:44:00"); + + assertEquals(LocalTime.parse("19:44:00"), stringValue.timeValue()); + assertEquals("\"19:44:00\"", stringValue.toString()); + + SemanticCheckException exception = + assertThrows(SemanticCheckException.class, + () -> new ExprStringValue("01:01:0").timeValue()); + assertEquals("time:01:01:0 in unsupported format, please use HH:mm:ss", + exception.getMessage()); + } } From c001615781da32c21d77823637bc80b3134df421 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Mon, 28 Sep 2020 17:29:42 -0700 Subject: [PATCH 41/42] removing implicit def for keyword in parser --- sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 index 02ad60979e..ee72853206 100644 --- a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 @@ -51,14 +51,11 @@ ident : DOT? ID | DOUBLE_QUOTE_ID | BACKTICK_QUOTE_ID - | keywordsCanBeId ; keywordsCanBeId : FULL | FIELD | D | T | TS // OD SQL and ODBC special | COUNT | SUM | AVG | MAX | MIN - | ADDDATE | DATE | DATE_ADD | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS - | HOUR | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC - | TIMESTAMP | TO_DAYS | YEAR + | TIMESTAMP | DATE | TIME ; \ No newline at end of file From 104e6b9d64c21e84b48bbd2e6e79c92a22c9c073 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan <> Date: Mon, 28 Sep 2020 17:59:56 -0700 Subject: [PATCH 42/42] add dayofweek --- sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 index ee72853206..6ab88d4cb3 100644 --- a/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 +++ b/sql/src/main/antlr/OpenDistroSQLIdentifierParser.g4 @@ -57,5 +57,5 @@ keywordsCanBeId : FULL | FIELD | D | T | TS // OD SQL and ODBC special | COUNT | SUM | AVG | MAX | MIN - | TIMESTAMP | DATE | TIME + | TIMESTAMP | DATE | TIME | DAYOFWEEK ; \ No newline at end of file