From 939539f6c5f0c1562c2ba784e2926d4e9520a7a4 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 6 Oct 2022 20:27:29 -0700 Subject: [PATCH 01/14] Add functions `ADDTIME` and `SUBTIME`. Signed-off-by: Yury-Fridlyand --- .../expression/datetime/DateTimeFunction.java | 144 +++++++----------- .../expression/datetime/DateTimeTestBase.java | 28 +++- docs/user/dql/functions.rst | 121 ++------------- docs/user/ppl/functions/datetime.rst | 115 ++------------ .../sql/sql/DateTimeFunctionIT.java | 19 --- ppl/src/main/antlr/OpenSearchPPLParser.g4 | 58 ++----- sql/src/main/antlr/OpenSearchSQLParser.g4 | 9 ++ 7 files changed, 126 insertions(+), 368 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index df4dd0a96b5..f33534801e6 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -128,7 +128,6 @@ public void register(BuiltinFunctionRepository repository) { repository.register(second()); repository.register(subdate()); repository.register(subtime()); - repository.register(sysdate()); repository.register(time()); repository.register(time_to_sec()); repository.register(timestamp()); @@ -250,38 +249,22 @@ private DefaultFunctionResolver adddate() { */ private DefaultFunctionResolver addtime() { return define(BuiltinFunctionName.ADDTIME.getName(), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - TIME, TIME, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - TIME, TIME, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - TIME, TIME, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - TIME, TIME, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATETIME, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATETIME, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATETIME, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATETIME, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATE, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATE, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATE, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, DATE, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, TIMESTAMP, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, TIMESTAMP, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, TIMESTAMP, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), - DATETIME, TIMESTAMP, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, TIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, DATE), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, TIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, DATE), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, TIMESTAMP) ); } @@ -568,38 +551,22 @@ private DefaultFunctionResolver subdate() { */ private DefaultFunctionResolver subtime() { return define(BuiltinFunctionName.SUBTIME.getName(), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - TIME, TIME, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - TIME, TIME, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - TIME, TIME, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - TIME, TIME, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATETIME, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATETIME, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATETIME, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATETIME, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATE, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATE, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATE, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, DATE, TIMESTAMP), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, TIMESTAMP, TIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, TIMESTAMP, DATE), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, TIMESTAMP, DATETIME), - implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), - DATETIME, TIMESTAMP, TIMESTAMP) + impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, DATE), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, DATE), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, TIMESTAMP) ); } @@ -742,34 +709,34 @@ private ExprValue exprAddDateDays(ExprValue date, ExprValue days) { /** * Adds or subtracts time to/from date and returns the result. * - * @param functionProperties A FunctionProperties object. - * @param temporal A Date/Time/Datetime/Timestamp value to change. - * @param temporalDelta A Date/Time/Datetime/Timestamp object to add/subtract time from. - * @param isAdd A flag: true to add, false to subtract. + * @param date A Date/Time/Datetime/Timestamp value to change. + * @param time A Date/Time/Datetime/Timestamp object to add/subtract time from. + * @param add A flag: true to add, false to subtract. * @return A value calculated. */ - private ExprValue exprApplyTime(FunctionProperties functionProperties, - ExprValue temporal, ExprValue temporalDelta, Boolean isAdd) { - var interval = Duration.between(LocalTime.MIN, temporalDelta.timeValue()); - var result = isAdd - ? extractDateTime(temporal, functionProperties).plus(interval) - : extractDateTime(temporal, functionProperties).minus(interval); - return temporal.type() == TIME - ? new ExprTimeValue(result.toLocalTime()) - : new ExprDatetimeValue(result); + private ExprValue exprApplyTime(ExprValue date, ExprValue time, Boolean add) { + var timeToAdd = time.type() == TIME + ? time.timeValue() + : time.datetimeValue().toLocalTime(); + var dt = date.type() == TIME + ? LocalDate.now().atTime(date.timeValue()) + : date.datetimeValue(); + var interval = Duration.between(LocalTime.MIN, timeToAdd); + dt = add ? dt.plus(interval) : dt.minus(interval); + return date.type() == TIME + ? new ExprTimeValue(dt.toLocalTime()) + : new ExprDatetimeValue(dt); } /** * Adds time to date and returns the result. * - * @param functionProperties A FunctionProperties object. - * @param temporal A Date/Time/Datetime/Timestamp value to change. - * @param temporalDelta A Date/Time/Datetime/Timestamp object to add time from. + * @param date A Date/Time/Datetime/Timestamp value to change. + * @param time A Date/Time/Datetime/Timestamp object to add time from. * @return A value calculated. */ - private ExprValue exprAddTime(FunctionProperties functionProperties, - ExprValue temporal, ExprValue temporalDelta) { - return exprApplyTime(functionProperties, temporal, temporalDelta, true); + private ExprValue exprAddTime(ExprValue date, ExprValue time) { + return exprApplyTime(date, time, true); } /** @@ -1159,13 +1126,12 @@ private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { /** * Subtracts expr2 from expr1 and returns the result. * - * @param temporal A Date/Time/Datetime/Timestamp value to change. - * @param temporalDelta A Date/Time/Datetime/Timestamp to subtract time from. + * @param date A Date/Time/Datetime/Timestamp value to change. + * @param time A Date/Time/Datetime/Timestamp to subtract time from. * @return A value calculated. */ - private ExprValue exprSubTime(FunctionProperties functionProperties, - ExprValue temporal, ExprValue temporalDelta) { - return exprApplyTime(functionProperties, temporal, temporalDelta, false); + private ExprValue exprSubTime(ExprValue date, ExprValue time) { + return exprApplyTime(date, time, false); } /** diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java index 38beaad1315..08004a84dc4 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java @@ -6,6 +6,7 @@ package org.opensearch.sql.expression.datetime; import static org.opensearch.sql.data.model.ExprValueUtils.fromObjectValue; +import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE; import java.time.Instant; import java.time.LocalDate; @@ -81,6 +82,17 @@ protected String fromUnixTime(Double value, String format) { .valueOf().stringValue(); } + protected FunctionExpression addtime(Expression date, Expression interval) { + var func = functionRepository.resolve(new FunctionSignature(new FunctionName("addtime"), + List.of(date.type(), interval.type()))); + return (FunctionExpression)func.apply(List.of(date, interval)); + } + + protected ExprValue addtime(Temporal first, Temporal second) { + return addtime(DSL.literal(fromObjectValue(first)), DSL.literal(fromObjectValue(second))) + .valueOf(null); + } + protected FunctionExpression maketime(Expression hour, Expression minute, Expression second) { return (FunctionExpression) functionRepository.compile( @@ -167,8 +179,18 @@ protected Double unixTimeStampOf(LocalDateTime value) { .valueOf().doubleValue(); } - protected Double unixTimeStampOf(Instant value) { - return unixTimeStampOf(DSL.literal(new ExprTimestampValue(value))) - .valueOf().doubleValue(); + protected FunctionExpression subtime(Expression date, Expression interval) { + var func = functionRepository.resolve(new FunctionSignature(new FunctionName("subtime"), + List.of(date.type(), interval.type()))); + return (FunctionExpression)func.apply(List.of(date, interval)); + } + + protected ExprValue subtime(Temporal first, Temporal second) { + return subtime(DSL.literal(fromObjectValue(first)), DSL.literal(fromObjectValue(second))) + .valueOf(null); + } + + protected ExprValue eval(Expression expression) { + return expression.valueOf(env); } } diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index f7383d862d5..d9f8df0c23c 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -893,45 +893,13 @@ Antonyms: `SUBTIME`_ Example:: - os> SELECT ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0 ` + os> SELECT ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0`, ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0`, ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' + '23:59:59'`, ADDTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' + '00:05:42'` fetched rows / total rows = 1/1 - +---------------------+ - | '2008-12-12' + 0 | - |---------------------| - | 2008-12-12 00:00:00 | - +---------------------+ - - os> SELECT ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0` - fetched rows / total rows = 1/1 - +------------------+ - | '23:59:59' + 0 | - |------------------| - | 23:59:59 | - +------------------+ - - os> SELECT ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' + '23:59:59'` - fetched rows / total rows = 1/1 - +-----------------------------+ - | '2004-01-01' + '23:59:59' | - |-----------------------------| - | 2004-01-01 23:59:59 | - +-----------------------------+ - - os> SELECT ADDTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' + '00:05:42'` - fetched rows / total rows = 1/1 - +---------------------------+ - | '10:20:30' + '00:05:42' | - |---------------------------| - | 10:26:12 | - +---------------------------+ - - os> SELECT ADDTIME(TIMESTAMP('2007-02-28 10:20:30'), DATETIME('2002-03-04 20:40:50')) AS `'2007-02-28 10:20:30' + '20:40:50'` - fetched rows / total rows = 1/1 - +--------------------------------------+ - | '2007-02-28 10:20:30' + '20:40:50' | - |--------------------------------------| - | 2007-03-01 07:01:20 | - +--------------------------------------+ + +---------------------+------------------+-----------------------------+---------------------------+ + | '2008-12-12' + 0 | '23:59:59' + 0 | '2004-01-01' + '23:59:59' | '10:20:30' + '00:05:42' | + |---------------------+------------------+-----------------------------+---------------------------| + | 2008-12-12 00:00:00 | 23:59:59 | 2004-01-01 23:59:59 | 10:26:12 | + +---------------------+------------------+-----------------------------+---------------------------+ CONVERT_TZ @@ -2039,80 +2007,19 @@ Argument type: DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME Return type map: -(DATE/DATETIME/TIMESTAMP, DATE/DATETIME/TIMESTAMP/TIME) -> DATETIME - -(TIME, DATE/DATETIME/TIMESTAMP/TIME) -> TIME - -Antonyms: `ADDTIME`_ - -Example:: - - os> SELECT SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' - 0` - fetched rows / total rows = 1/1 - +---------------------+ - | '2008-12-12' - 0 | - |---------------------| - | 2008-12-12 00:00:00 | - +---------------------+ - - os> SELECT SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' - 0` - fetched rows / total rows = 1/1 - +------------------+ - | '23:59:59' - 0 | - |------------------| - | 23:59:59 | - +------------------+ - - os> SELECT SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' - '23:59:59'` - fetched rows / total rows = 1/1 - +-----------------------------+ - | '2004-01-01' - '23:59:59' | - |-----------------------------| - | 2003-12-31 00:00:01 | - +-----------------------------+ - - os> SELECT SUBTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' - '00:05:42'` - fetched rows / total rows = 1/1 - +---------------------------+ - | '10:20:30' - '00:05:42' | - |---------------------------| - | 10:14:48 | - +---------------------------+ - - os> SELECT SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) AS `'2007-03-01 10:20:30' - '20:40:50'` - fetched rows / total rows = 1/1 - +--------------------------------------+ - | '2007-03-01 10:20:30' - '20:40:50' | - |--------------------------------------| - | 2007-02-28 13:39:40 | - +--------------------------------------+ - - -SYSDATE -------- - -Description ->>>>>>>>>>> - -Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss[.nnnnnn]'. -SYSDATE() returns the time at which it executes. This differs from the behavior for `NOW() <#now>`_, which returns a constant time that indicates the time at which the statement began to execute. -If the argument is given, it specifies a fractional seconds precision from 0 to 6, the return value includes a fractional seconds part of that many digits. - -Optional argument type: INTEGER - -Return type: DATETIME +DATE/DATETIME/TIMESTAMP, DATE/DATETIME/TIMESTAMP/TIME -> DATETIME -Specification: SYSDATE([INTEGER]) -> DATETIME +TIME, DATE/DATETIME/TIMESTAMP/TIME -> TIME Example:: - > SELECT SYSDATE() as value_1, SYSDATE(6) as value_2; + os> SELECT SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' - 0`, SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' - 0`, SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' - '23:59:59'`, SUBTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' - '00:05:42'` fetched rows / total rows = 1/1 - +---------------------+----------------------------+ - | value_1 | value_2 | - |---------------------+----------------------------| - | 2022-08-02 15:39:05 | 2022-08-02 15:39:05.123456 | - +---------------------+----------------------------+ + +---------------------+------------------+-----------------------------+---------------------------+ + | '2008-12-12' - 0 | '23:59:59' - 0 | '2004-01-01' - '23:59:59' | '10:20:30' - '00:05:42' | + |---------------------+------------------+-----------------------------+---------------------------| + | 2008-12-12 00:00:00 | 23:59:59 | 2003-12-31 00:00:01 | 10:14:48 | + +---------------------+------------------+-----------------------------+---------------------------+ TIME diff --git a/docs/user/ppl/functions/datetime.rst b/docs/user/ppl/functions/datetime.rst index 2cc83eba971..e713174a2ce 100644 --- a/docs/user/ppl/functions/datetime.rst +++ b/docs/user/ppl/functions/datetime.rst @@ -59,45 +59,13 @@ Antonyms: `SUBTIME`_ Example:: - os> source=people | eval `'2008-12-12' + 0` = ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) | fields `'2008-12-12' + 0` + os> source=people | eval `'2008-12-12' + 0` = ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')), `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')), `'2004-01-01' + '23:59:59'` = ADDTIME(DATE('2004-01-01'), TIME('23:59:59')), `'10:20:30' + '00:05:42'` = ADDTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'2008-12-12' + 0`, `'23:59:59' + 0`, `'2004-01-01' + '23:59:59'`, `'10:20:30' + '00:05:42'` fetched rows / total rows = 1/1 - +---------------------+ - | '2008-12-12' + 0 | - |---------------------| - | 2008-12-12 00:00:00 | - +---------------------+ - - os> source=people | eval `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' + 0` - fetched rows / total rows = 1/1 - +------------------+ - | '23:59:59' + 0 | - |------------------| - | 23:59:59 | - +------------------+ - - os> source=people | eval `'2004-01-01' + '23:59:59'` = ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) | fields `'2004-01-01' + '23:59:59'` - fetched rows / total rows = 1/1 - +-----------------------------+ - | '2004-01-01' + '23:59:59' | - |-----------------------------| - | 2004-01-01 23:59:59 | - +-----------------------------+ - - os> source=people | eval `'10:20:30' + '00:05:42'` = ADDTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'10:20:30' + '00:05:42'` - fetched rows / total rows = 1/1 - +---------------------------+ - | '10:20:30' + '00:05:42' | - |---------------------------| - | 10:26:12 | - +---------------------------+ - - os> source=people | eval `'2007-02-28 10:20:30' + '20:40:50'` = ADDTIME(TIMESTAMP('2007-02-28 10:20:30'), DATETIME('2002-03-04 20:40:50')) | fields `'2007-02-28 10:20:30' + '20:40:50'` - fetched rows / total rows = 1/1 - +--------------------------------------+ - | '2007-02-28 10:20:30' + '20:40:50' | - |--------------------------------------| - | 2007-03-01 07:01:20 | - +--------------------------------------+ + +---------------------+------------------+-----------------------------+---------------------------+ + | '2008-12-12' + 0 | '23:59:59' + 0 | '2004-01-01' + '23:59:59' | '10:20:30' + '00:05:42' | + |---------------------+------------------+-----------------------------+---------------------------| + | 2008-12-12 00:00:00 | 23:59:59 | 2004-01-01 23:59:59 | 10:26:12 | + +---------------------+------------------+-----------------------------+---------------------------+ CONVERT_TZ @@ -1164,72 +1132,13 @@ Antonyms: `ADDTIME`_ Example:: - os> source=people | eval `'2008-12-12' - 0` = SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) | fields `'2008-12-12' - 0` - fetched rows / total rows = 1/1 - +---------------------+ - | '2008-12-12' - 0 | - |---------------------| - | 2008-12-12 00:00:00 | - +---------------------+ - - os> source=people | eval `'23:59:59' - 0` = SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' - 0` - fetched rows / total rows = 1/1 - +------------------+ - | '23:59:59' - 0 | - |------------------| - | 23:59:59 | - +------------------+ - - os> source=people | eval `'2004-01-01' - '23:59:59'` = SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) | fields `'2004-01-01' - '23:59:59'` - fetched rows / total rows = 1/1 - +-----------------------------+ - | '2004-01-01' - '23:59:59' | - |-----------------------------| - | 2003-12-31 00:00:01 | - +-----------------------------+ - - os> source=people | eval `'10:20:30' - '00:05:42'` = SUBTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'10:20:30' - '00:05:42'` - fetched rows / total rows = 1/1 - +---------------------------+ - | '10:20:30' - '00:05:42' | - |---------------------------| - | 10:14:48 | - +---------------------------+ - - os> source=people | eval `'2007-03-01 10:20:30' - '20:40:50'` = SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) | fields `'2007-03-01 10:20:30' - '20:40:50'` - fetched rows / total rows = 1/1 - +--------------------------------------+ - | '2007-03-01 10:20:30' - '20:40:50' | - |--------------------------------------| - | 2007-02-28 13:39:40 | - +--------------------------------------+ - - -SYSDATE -------- - -Description ->>>>>>>>>>> - -Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss[.nnnnnn]'. -SYSDATE() returns the time at which it executes. This differs from the behavior for `NOW() <#now>`_, which returns a constant time that indicates the time at which the statement began to execute. -If the argument is given, it specifies a fractional seconds precision from 0 to 6, the return value includes a fractional seconds part of that many digits. - -Optional argument type: INTEGER - -Return type: DATETIME - -Specification: SYSDATE([INTEGER]) -> DATETIME - -Example:: - - > source=people | eval `value_1` = SYSDATE(), `value_2` = SYSDATE(6) | fields `value_1`, `value_2` + os> source=people | eval `'2008-12-12' - 0` = SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')), `'23:59:59' - 0` = SUBTIME(TIME('23:59:59'), DATE('2004-01-01')), `'2004-01-01' - '23:59:59'` = SUBTIME(DATE('2004-01-01'), TIME('23:59:59')), `'10:20:30' - '00:05:42'` = SUBTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'2008-12-12' - 0`, `'23:59:59' - 0`, `'2004-01-01' - '23:59:59'`, `'10:20:30' - '00:05:42'` fetched rows / total rows = 1/1 - +---------------------+----------------------------+ - | value_1 | value_2 | - |---------------------+----------------------------| - | 2022-08-02 15:39:05 | 2022-08-02 15:39:05.123456 | - +---------------------+----------------------------+ + +---------------------+------------------+-----------------------------+---------------------------+ + | '2008-12-12' - 0 | '23:59:59' - 0 | '2004-01-01' - '23:59:59' | '10:20:30' - '00:05:42' | + |---------------------+------------------+-----------------------------+---------------------------| + | 2008-12-12 00:00:00 | 23:59:59 | 2003-12-31 00:00:01 | 10:14:48 | + +---------------------+------------------+-----------------------------+---------------------------+ TIME diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java index f10596e21c3..fd87a6d4e3f 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java @@ -826,25 +826,6 @@ public void testUnixTimeStamp() throws IOException { } @Test - public void testPeriodAdd() throws IOException { - var result = executeQuery( - "select PERIOD_ADD(200801, 2) as f1, PERIOD_ADD(200801, -12) as f2"); - verifySchema(result, - schema("PERIOD_ADD(200801, 2)", "f1", "integer"), - schema("PERIOD_ADD(200801, -12)", "f2", "integer")); - verifyDataRows(result, rows(200803, 200701)); - } - - @Test - public void testPeriodDiff() throws IOException { - var result = executeQuery( - "select PERIOD_DIFF(200802, 200703) as f1, PERIOD_DIFF(200802, 201003) as f2"); - verifySchema(result, - schema("PERIOD_DIFF(200802, 200703)", "f1", "integer"), - schema("PERIOD_DIFF(200802, 201003)", "f2", "integer")); - verifyDataRows(result, rows(11, -25)); - } - public void testAddTime() throws IOException { var result = executeQuery("SELECT" + " ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0`," diff --git a/ppl/src/main/antlr/OpenSearchPPLParser.g4 b/ppl/src/main/antlr/OpenSearchPPLParser.g4 index 9cb539cfbaa..edc33983a4a 100644 --- a/ppl/src/main/antlr/OpenSearchPPLParser.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLParser.g4 @@ -428,53 +428,17 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : ADDDATE - | ADDTIME - | CONVERT_TZ - | CURRENT_DATE - | CURRENT_TIME - | CURRENT_TIMESTAMP - | DATE - | DATE_ADD - | DATE_FORMAT - | DATE_SUB - | DATETIME - | DAY - | DAYNAME - | DAYOFMONTH - | DAYOFWEEK - | DAYOFYEAR - | CURDATE - | CURTIME - | FROM_DAYS - | FROM_UNIXTIME - | HOUR - | LOCALTIME - | LOCALTIMESTAMP - | MAKEDATE - | MAKETIME - | MICROSECOND - | MINUTE - | MONTH - | MONTHNAME - | NOW - | PERIOD_ADD - | PERIOD_DIFF - | QUARTER - | SECOND - | SUBDATE - | SUBTIME - | SYSDATE - | TIME - | TIME_TO_SEC - | TIMESTAMP - | TO_DAYS - | UNIX_TIMESTAMP - | UTC_DATE - | UTC_TIME - | UTC_TIMESTAMP - | WEEK - | YEAR + : ADDDATE | ADDTIME | CONVERT_TZ | DATE | DATE_ADD | DATE_FORMAT | DATE_SUB + | DATETIME | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | FROM_UNIXTIME + | HOUR | MAKEDATE | MAKETIME | MICROSECOND | MINUTE | MONTH | MONTHNAME + | QUARTER | SECOND | SUBDATE | SUBTIME | SYSDATE | TIME | TIME_TO_SEC + | TIMESTAMP | TO_DAYS | UNIX_TIMESTAMP | WEEK | YEAR + ; + +// Functions which value could be cached in scope of a single query +constantFunctionName + : datetimeConstantLiteral + | CURDATE | CURTIME | NOW ; /** condition function return boolean value */ diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 1598e7676cb..3076727b55e 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -411,6 +411,15 @@ trigonometricFunctionName ; dateTimeFunctionName + : ADDDATE | ADDTIME | CONVERT_TZ | DATE | DATE_ADD | DATE_FORMAT | DATE_SUB + | DATETIME | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | FROM_UNIXTIME + | HOUR | MAKEDATE | MAKETIME | MICROSECOND | MINUTE | MONTH | MONTHNAME + | QUARTER | SECOND | SUBDATE | SUBTIME | SYSDATE | TIME | TIME_TO_SEC + | TIMESTAMP | TO_DAYS | UNIX_TIMESTAMP | WEEK | YEAR + ; + +// Functions which value could be cached in scope of a single query +constantFunctionName : datetimeConstantLiteral | ADDDATE | ADDTIME From 3b01e6b202a8e0b9bee56f260c1c19b06d901810 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Tue, 11 Oct 2022 20:25:40 -0700 Subject: [PATCH 02/14] Update docs - rework on examples. Signed-off-by: Yury-Fridlyand --- docs/user/dql/functions.rst | 93 +++++++++++++++++++++++----- docs/user/ppl/functions/datetime.rst | 88 ++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 26 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index d9f8df0c23c..3e363efb820 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -893,13 +893,45 @@ Antonyms: `SUBTIME`_ Example:: - os> SELECT ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0`, ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0`, ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' + '23:59:59'`, ADDTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' + '00:05:42'` + os> SELECT ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0` fetched rows / total rows = 1/1 - +---------------------+------------------+-----------------------------+---------------------------+ - | '2008-12-12' + 0 | '23:59:59' + 0 | '2004-01-01' + '23:59:59' | '10:20:30' + '00:05:42' | - |---------------------+------------------+-----------------------------+---------------------------| - | 2008-12-12 00:00:00 | 23:59:59 | 2004-01-01 23:59:59 | 10:26:12 | - +---------------------+------------------+-----------------------------+---------------------------+ + +---------------------+ + | '2008-12-12' + 0 | + |---------------------| + | 2008-12-12 00:00:00 | + +---------------------+ + + os> SELECT ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0` + fetched rows / total rows = 1/1 + +------------------+ + | '23:59:59' + 0 | + |------------------| + | 23:59:59 | + +------------------+ + + os> SELECT ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' + '23:59:59'` + fetched rows / total rows = 1/1 + +-----------------------------+ + | '2004-01-01' + '23:59:59' | + |-----------------------------| + | 2004-01-01 23:59:59 | + +-----------------------------+ + + os> SELECT ADDTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' + '00:05:42'` + fetched rows / total rows = 1/1 + +---------------------------+ + | '10:20:30' + '00:05:42' | + |---------------------------| + | 10:26:12 | + +---------------------------+ + + os> SELECT ADDTIME(TIMESTAMP('2007-02-28 10:20:30'), DATETIME('2002-03-04 20:40:50')) AS `'2007-02-28 10:20:30' + '20:40:50'` + fetched rows / total rows = 1/1 + +--------------------------------------+ + | '2007-02-28 10:20:30' + '20:40:50' | + |--------------------------------------| + | 2007-03-01 07:01:20 | + +--------------------------------------+ CONVERT_TZ @@ -2007,20 +2039,53 @@ Argument type: DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME Return type map: -DATE/DATETIME/TIMESTAMP, DATE/DATETIME/TIMESTAMP/TIME -> DATETIME +(DATE/DATETIME/TIMESTAMP, DATE/DATETIME/TIMESTAMP/TIME) -> DATETIME + +(TIME, DATE/DATETIME/TIMESTAMP/TIME) -> TIME -TIME, DATE/DATETIME/TIMESTAMP/TIME -> TIME +Antonyms: `ADDTIME`_ Example:: - os> SELECT SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' - 0`, SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' - 0`, SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' - '23:59:59'`, SUBTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' - '00:05:42'` + os> SELECT SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' - 0` fetched rows / total rows = 1/1 - +---------------------+------------------+-----------------------------+---------------------------+ - | '2008-12-12' - 0 | '23:59:59' - 0 | '2004-01-01' - '23:59:59' | '10:20:30' - '00:05:42' | - |---------------------+------------------+-----------------------------+---------------------------| - | 2008-12-12 00:00:00 | 23:59:59 | 2003-12-31 00:00:01 | 10:14:48 | - +---------------------+------------------+-----------------------------+---------------------------+ + +---------------------+ + | '2008-12-12' - 0 | + |---------------------| + | 2008-12-12 00:00:00 | + +---------------------+ + + os> SELECT SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' - 0` + fetched rows / total rows = 1/1 + +------------------+ + | '23:59:59' - 0 | + |------------------| + | 23:59:59 | + +------------------+ + + os> SELECT SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) AS `'2004-01-01' - '23:59:59'` + fetched rows / total rows = 1/1 + +-----------------------------+ + | '2004-01-01' - '23:59:59' | + |-----------------------------| + | 2003-12-31 00:00:01 | + +-----------------------------+ + os> SELECT SUBTIME(TIME('10:20:30'), TIME('00:05:42')) AS `'10:20:30' - '00:05:42'` + fetched rows / total rows = 1/1 + +---------------------------+ + | '10:20:30' - '00:05:42' | + |---------------------------| + | 10:14:48 | + +---------------------------+ + + os> SELECT SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) AS `'2007-03-01 10:20:30' - '20:40:50'` + fetched rows / total rows = 1/1 + +-----------------------------------------+ + | `'2007-03-01 10:20:30' - '20:40:50'` | + |-----------------------------------------| + | 2007-02-28 13:39:40 | + +-----------------------------------------+ TIME ---- diff --git a/docs/user/ppl/functions/datetime.rst b/docs/user/ppl/functions/datetime.rst index e713174a2ce..ae893a5e8b0 100644 --- a/docs/user/ppl/functions/datetime.rst +++ b/docs/user/ppl/functions/datetime.rst @@ -59,13 +59,45 @@ Antonyms: `SUBTIME`_ Example:: - os> source=people | eval `'2008-12-12' + 0` = ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')), `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')), `'2004-01-01' + '23:59:59'` = ADDTIME(DATE('2004-01-01'), TIME('23:59:59')), `'10:20:30' + '00:05:42'` = ADDTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'2008-12-12' + 0`, `'23:59:59' + 0`, `'2004-01-01' + '23:59:59'`, `'10:20:30' + '00:05:42'` + os> source=people | eval `'2008-12-12' + 0` = ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) | fields `'2008-12-12' + 0` fetched rows / total rows = 1/1 - +---------------------+------------------+-----------------------------+---------------------------+ - | '2008-12-12' + 0 | '23:59:59' + 0 | '2004-01-01' + '23:59:59' | '10:20:30' + '00:05:42' | - |---------------------+------------------+-----------------------------+---------------------------| - | 2008-12-12 00:00:00 | 23:59:59 | 2004-01-01 23:59:59 | 10:26:12 | - +---------------------+------------------+-----------------------------+---------------------------+ + +---------------------+ + | '2008-12-12' + 0 | + |---------------------| + | 2008-12-12 00:00:00 | + +---------------------+ + + os> source=people | `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' + 0` + fetched rows / total rows = 1/1 + +------------------+ + | '23:59:59' + 0 | + |------------------| + | 23:59:59 | + +------------------+ + + os> source=people | eval `'2004-01-01' + '23:59:59'` = ADDTIME(DATE('2004-01-01'), TIME('23:59:59')) | fields `'2004-01-01' + '23:59:59'` + fetched rows / total rows = 1/1 + +-----------------------------+ + | '2004-01-01' + '23:59:59' | + |-----------------------------| + | 2004-01-01 23:59:59 | + +-----------------------------+ + + os> source=people | eval `'10:20:30' + '00:05:42'` = ADDTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'10:20:30' + '00:05:42'` + fetched rows / total rows = 1/1 + +---------------------------+ + | '10:20:30' + '00:05:42' | + |---------------------------| + | 10:26:12 | + +---------------------------+ + + os> source=people | eval `'2007-02-28 10:20:30' + '20:40:50'` = ADDTIME(TIMESTAMP('2007-02-28 10:20:30'), DATETIME('2002-03-04 20:40:50')) | fields `'2007-02-28 10:20:30' + '20:40:50'` + fetched rows / total rows = 1/1 + +--------------------------------------+ + | '2007-02-28 10:20:30' + '20:40:50' | + |--------------------------------------| + | 2007-03-01 07:01:20 | + +--------------------------------------+ CONVERT_TZ @@ -1132,13 +1164,45 @@ Antonyms: `ADDTIME`_ Example:: - os> source=people | eval `'2008-12-12' - 0` = SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')), `'23:59:59' - 0` = SUBTIME(TIME('23:59:59'), DATE('2004-01-01')), `'2004-01-01' - '23:59:59'` = SUBTIME(DATE('2004-01-01'), TIME('23:59:59')), `'10:20:30' - '00:05:42'` = SUBTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'2008-12-12' - 0`, `'23:59:59' - 0`, `'2004-01-01' - '23:59:59'`, `'10:20:30' - '00:05:42'` + os> source=people | eval `'2008-12-12' - 0` = SUBTIME(DATE('2008-12-12'), DATE('2008-11-15')) | fields `'2008-12-12' - 0` + fetched rows / total rows = 1/1 + +---------------------+ + | '2008-12-12' - 0 | + |---------------------| + | 2008-12-12 00:00:00 | + +---------------------+ + + os> source=people | eval `'23:59:59' - 0` = SUBTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' - 0` + fetched rows / total rows = 1/1 + +------------------+ + | '23:59:59' - 0 | + |------------------| + | 23:59:59 | + +------------------+ + + os> source=people | eval `'2004-01-01' - '23:59:59'` = SUBTIME(DATE('2004-01-01'), TIME('23:59:59')) | fields `'2004-01-01' - '23:59:59'` + fetched rows / total rows = 1/1 + +-----------------------------+ + | '2004-01-01' - '23:59:59' | + |-----------------------------| + | 2003-12-31 00:00:01 | + +-----------------------------+ + + os> source=people | eval `'10:20:30' - '00:05:42'` = SUBTIME(TIME('10:20:30'), TIME('00:05:42')) | fields `'10:20:30' - '00:05:42'` + fetched rows / total rows = 1/1 + +---------------------------+ + | '10:20:30' - '00:05:42' | + |---------------------------| + | 10:14:48 | + +---------------------------+ + + os> source=people | eval `'2007-03-01 10:20:30' - '20:40:50'` = SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) | fields `'2007-03-01 10:20:30' - '20:40:50'` fetched rows / total rows = 1/1 - +---------------------+------------------+-----------------------------+---------------------------+ - | '2008-12-12' - 0 | '23:59:59' - 0 | '2004-01-01' - '23:59:59' | '10:20:30' - '00:05:42' | - |---------------------+------------------+-----------------------------+---------------------------| - | 2008-12-12 00:00:00 | 23:59:59 | 2003-12-31 00:00:01 | 10:14:48 | - +---------------------+------------------+-----------------------------+---------------------------+ + +-----------------------------------------+ + | `'2007-03-01 10:20:30' - '20:40:50'` | + |-----------------------------------------| + | 2007-02-28 13:39:40 | + +-----------------------------------------+ TIME From fbabe78ad5ac65981c0ec241465479f1f58848b8 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Wed, 12 Oct 2022 19:16:32 -0700 Subject: [PATCH 03/14] Update `ExprTimeValue` by `datetimeValue` and other interfaces. Add corresponding tests. Signed-off-by: Yury-Fridlyand --- .../sql/data/model/ExprTimeValue.java | 17 +++++++++++++++ .../sql/data/model/DateTimeValueTest.java | 21 ++++--------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java b/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java index d77a2615d26..a1019acdbbb 100644 --- a/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java +++ b/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java @@ -13,7 +13,9 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Objects; import lombok.RequiredArgsConstructor; @@ -70,6 +72,21 @@ public Instant timestampValue(FunctionProperties functionProperties) { .toInstant(); } + @Override + public LocalDate dateValue() { + return LocalDate.now(); + } + + @Override + public LocalDateTime datetimeValue() { + return LocalDateTime.of(dateValue(), timeValue()); + } + + @Override + public Instant timestampValue() { + return ZonedDateTime.of(dateValue(), timeValue(), ZoneId.systemDefault()).toInstant(); + } + @Override public String toString() { return String.format("TIME '%s'", value()); diff --git a/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java b/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java index a335478e193..4fc4a7d563f 100644 --- a/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java +++ b/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java @@ -32,23 +32,10 @@ public void timeValueInterfaceTest() { assertEquals(TIME, timeValue.type()); assertEquals(LocalTime.parse("01:01:01"), timeValue.timeValue()); - // It is prohibited to acquire values which include date part from `ExprTimeValue` - // without a FunctionProperties object - var exception = assertThrows(ExpressionEvaluationException.class, timeValue::dateValue); - assertEquals("invalid to get dateValue from value of type TIME", exception.getMessage()); - exception = assertThrows(ExpressionEvaluationException.class, timeValue::datetimeValue); - assertEquals("invalid to get datetimeValue from value of type TIME", exception.getMessage()); - exception = assertThrows(ExpressionEvaluationException.class, timeValue::timestampValue); - assertEquals("invalid to get timestampValue from value of type TIME", exception.getMessage()); - - var functionProperties = new FunctionProperties(); - var today = LocalDate.now(functionProperties.getQueryStartClock()); - - assertEquals(today, timeValue.dateValue(functionProperties)); - assertEquals(today.atTime(1, 1, 1), timeValue.datetimeValue(functionProperties)); - assertEquals(ZonedDateTime.of(LocalTime.parse("01:01:01").atDate(today), - ExprTimestampValue.ZONE).toInstant(), timeValue.timestampValue(functionProperties)); - + assertEquals(LocalDate.now(), timeValue.dateValue()); + assertEquals(LocalDate.now().atTime(1, 1, 1), timeValue.datetimeValue()); + assertEquals(ZonedDateTime.of(LocalTime.parse("01:01:01").atDate(LocalDate.now()), + ZoneId.systemDefault()).toInstant(), timeValue.timestampValue()); assertEquals("01:01:01", timeValue.value()); assertEquals("TIME '01:01:01'", timeValue.toString()); exception = assertThrows(ExpressionEvaluationException.class, From 533281cf367f141f4019439456d6108ffed0d3b5 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 13 Oct 2022 17:57:13 -0700 Subject: [PATCH 04/14] Update `TIMESTAMP` function implementation and signatures. Signed-off-by: Yury-Fridlyand --- .../expression/datetime/DateTimeFunction.java | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index f33534801e6..cf9a9772619 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -598,15 +598,32 @@ private DefaultFunctionResolver time_to_sec() { /** * Extracts the timestamp of a date and time value. - * Also to construct a date type. The supported signatures: - * STRING/DATE/DATETIME/TIMESTAMP -> DATE + * + * DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP + * DATE/TIME/DATETIME/TIMESTAMP, DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP */ private DefaultFunctionResolver timestamp() { return define(BuiltinFunctionName.TIMESTAMP.getName(), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIME), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIMESTAMP)); + impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIMESTAMP)); } /** @@ -1151,15 +1168,23 @@ private ExprValue exprTime(ExprValue exprValue) { /** * Timestamp implementation for ExprValue. * - * @param exprValue ExprValue of Timestamp type or String type. + * @param exprValue ExprValue of Timestamp. * @return ExprValue. */ private ExprValue exprTimestamp(ExprValue exprValue) { - if (exprValue instanceof ExprStringValue) { - return new ExprTimestampValue(exprValue.stringValue()); - } else { - return new ExprTimestampValue(exprValue.timestampValue()); - } + return new ExprTimestampValue(exprValue.timestampValue()); + } + + /** + * Timestamp implementation for two arguments. It adds the time expression exprValue2 + * to the expression exprValue2 and returns the result as a timestamp value. + * + * @param exprValue1 ExprValue of Timestamp type or String type. + * @param exprValue2 ExprValue of Timestamp type or String type. + * @return ExprValue. + */ + private ExprValue exprTimestampEx(ExprValue exprValue1, ExprValue exprValue2) { + return exprAddTime(exprTimestamp(exprValue1), exprTimestamp(exprValue2)); } /** From 80affb7179d3e2aeb12fa16cb88111f7734130a9 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Fri, 14 Oct 2022 09:58:33 -0700 Subject: [PATCH 05/14] Modify function to accept strings. Signed-off-by: Yury-Fridlyand --- .../expression/datetime/DateTimeFunction.java | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index cf9a9772619..5ade73d71bc 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -598,32 +598,47 @@ private DefaultFunctionResolver time_to_sec() { /** * Extracts the timestamp of a date and time value. + * Input strings may contain a timestamp only in format 'yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]' * - * DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP - * DATE/TIME/DATETIME/TIMESTAMP, DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP + * STRING/DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP + * STRING/DATE/TIME/DATETIME/TIMESTAMP, STRING/DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP */ private DefaultFunctionResolver timestamp() { return define(BuiltinFunctionName.TIMESTAMP.getName(), + impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATE), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIME), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, STRING), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, DATE), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, TIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATE), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIME), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATE), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIME), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATE), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATETIME, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATETIME, TIMESTAMP), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, STRING), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATE), impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIMESTAMP)); + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIMESTAMP, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIMESTAMP, TIMESTAMP)); } /** @@ -1172,7 +1187,11 @@ private ExprValue exprTime(ExprValue exprValue) { * @return ExprValue. */ private ExprValue exprTimestamp(ExprValue exprValue) { - return new ExprTimestampValue(exprValue.timestampValue()); + if (exprValue instanceof ExprStringValue) { + return new ExprTimestampValue(exprValue.stringValue()); + } else { + return new ExprTimestampValue(exprValue.timestampValue()); + } } /** From e7db9700d83427fa4ad4439323ae4e3c13262daa Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Sun, 16 Oct 2022 11:22:44 -0700 Subject: [PATCH 06/14] Return `NULL` on invalid string input. Signed-off-by: Yury-Fridlyand --- .../sql/expression/datetime/DateTimeFunction.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index 5ade73d71bc..2b25827d850 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -1188,7 +1188,11 @@ private ExprValue exprTime(ExprValue exprValue) { */ private ExprValue exprTimestamp(ExprValue exprValue) { if (exprValue instanceof ExprStringValue) { - return new ExprTimestampValue(exprValue.stringValue()); + try { + return new ExprTimestampValue(exprValue.stringValue()); + } catch (SemanticCheckException ignored) { + return ExprNullValue.of(); + } } else { return new ExprTimestampValue(exprValue.timestampValue()); } From df0b27c64b5060a7fb4367751a73531f9fdad33e Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 20 Oct 2022 15:10:45 -0700 Subject: [PATCH 07/14] Add unit tests. Signed-off-by: Yury-Fridlyand --- .../expression/datetime/DateTimeFunction.java | 4 +- .../expression/datetime/TimestampTest.java | 186 ++++++++++++++++++ 2 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index 2b25827d850..16c193ecbe7 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -1199,8 +1199,8 @@ private ExprValue exprTimestamp(ExprValue exprValue) { } /** - * Timestamp implementation for two arguments. It adds the time expression exprValue2 - * to the expression exprValue2 and returns the result as a timestamp value. + * Timestamp implementation for two arguments. It extracts time expression from exprValue2 + * and adds it to the expression exprValue1 and returns the result as a timestamp value. * * @param exprValue1 ExprValue of Timestamp type or String type. * @param exprValue2 ExprValue of Timestamp type or String type. diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java new file mode 100644 index 00000000000..68e7e59897c --- /dev/null +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java @@ -0,0 +1,186 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.sql.expression.datetime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opensearch.sql.data.model.ExprNullValue; +import org.opensearch.sql.data.model.ExprTimestampValue; +import org.opensearch.sql.data.model.ExprValue; +import org.opensearch.sql.data.model.ExprValueUtils; +import org.opensearch.sql.expression.DSL; +import org.opensearch.sql.expression.Expression; +import org.opensearch.sql.expression.ExpressionTestBase; +import org.opensearch.sql.expression.env.Environment; + +@ExtendWith(MockitoExtension.class) +public class TimestampTest extends ExpressionTestBase { + + @Mock + Environment env; + + @Test + public void timestamp_one_arg_string() { + var expr = dsl.timestamp(DSL.literal("1961-04-12 09:07:00")); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(new ExprTimestampValue("1961-04-12 09:07:00"), expr.valueOf(env)); + + expr = dsl.timestamp(DSL.literal("1961-04-12 09:07:00.123456")); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0, 123456000), + expr.valueOf(env).datetimeValue()); + } + + @Test + public void timestamp_one_arg_string_invalid_format() { + // Feb 30th + var expr = dsl.timestamp(DSL.literal("1984-02-30 12:20:42")); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(ExprNullValue.of(), expr.valueOf(env)); + + // 24:00:00 + expr = dsl.timestamp(DSL.literal("1984-02-10 24:00:00")); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(ExprNullValue.of(), expr.valueOf(env)); + + // 2 digit year + expr = dsl.timestamp(DSL.literal("84-02-10 12:20:42")); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(ExprNullValue.of(), expr.valueOf(env)); + } + + @Test + public void timestamp_one_arg_time() { + var expr = dsl.timestamp(dsl.time(DSL.literal("22:33:44"))); + assertEquals(TIMESTAMP, expr.type()); + var refValue = LocalDate.now().atTime(LocalTime.of(22, 33, 44)) + .atZone(ExprTimestampValue.ZONE).toInstant(); + assertEquals(new ExprTimestampValue(refValue), expr.valueOf(env)); + } + + @Test + public void timestamp_one_arg_date() { + var expr = dsl.timestamp(dsl.date(DSL.literal("2077-12-15"))); + assertEquals(TIMESTAMP, expr.type()); + var refValue = LocalDate.of(2077, 12, 15).atStartOfDay() + .atZone(ExprTimestampValue.ZONE).toInstant(); + assertEquals(new ExprTimestampValue(refValue), expr.valueOf(env)); + } + + @Test + public void timestamp_one_arg_datetime() { + var expr = dsl.timestamp(dsl.datetime(DSL.literal("1961-04-12 09:07:00"))); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0), expr.valueOf(env).datetimeValue()); + } + + @Test + public void timestamp_one_arg_timestamp() { + var refValue = new ExprTimestampValue(Instant.ofEpochSecond(10050042)); + var expr = dsl.timestamp(dsl.timestamp(DSL.literal(refValue))); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(refValue, expr.valueOf(env)); + } + + private static Instant dateTime2Instant(LocalDateTime dt) { + return dt.atZone(ExprTimestampValue.ZONE).toInstant(); + } + + private static ExprTimestampValue dateTime2ExprTs(LocalDateTime dt) { + return new ExprTimestampValue(dateTime2Instant(dt)); + } + + private static Stream getTestData() { + var today = LocalDate.now(); + // First argument of `TIMESTAMP` function, second argument and expected result value + return Stream.of( + // STRING and STRING/DATE/TIME/DATETIME/TIMESTAMP + Arguments.of("1961-04-12 09:07:00", "2077-12-15 01:48:00", + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of("1984-02-10 12:20:42", LocalDate.of(2077, 12, 21), + dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), + Arguments.of("1961-04-12 09:07:00", LocalTime.of(1, 48), + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of("2020-12-31 17:30:00", LocalDateTime.of(2077, 12, 21, 12, 20, 42), + dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), + Arguments.of("2020-12-31 17:30:00", Instant.ofEpochSecond(42), + dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))), + // DATE and STRING/DATE/TIME/DATETIME/TIMESTAMP + Arguments.of(LocalDate.of(2077, 12, 21), "2077-12-15 01:48:00", + dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 1, 48, 0))), + Arguments.of(LocalDate.of(2077, 12, 21), LocalDate.of(1984, 2, 3), + dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 0, 0, 0))), + Arguments.of(LocalDate.of(2077, 12, 21), LocalTime.of(22, 33, 44), + dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 22, 33, 44))), + Arguments.of(LocalDate.of(2077, 12, 21), LocalDateTime.of(1999, 9, 9, 22, 33, 44), + dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 22, 33, 44))), + Arguments.of(LocalDate.of(2077, 12, 21), Instant.ofEpochSecond(42), + dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 0, 0, 42))), + // TIME and STRING/DATE/TIME/DATETIME/TIMESTAMP + Arguments.of(LocalTime.of(9, 7, 0), "2077-12-15 01:48:00", + dateTime2ExprTs(today.atTime(LocalTime.of(10, 55, 0)))), + Arguments.of(LocalTime.of(12, 20, 42), LocalDate.of(2077, 12, 21), + dateTime2ExprTs(today.atTime(LocalTime.of(12, 20, 42)))), + Arguments.of(LocalTime.of(9, 7, 0), LocalTime.of(1, 48), + dateTime2ExprTs(today.atTime(LocalTime.of(10, 55, 0)))), + Arguments.of(LocalTime.of(17, 30, 0), LocalDateTime.of(2077, 12, 21, 12, 20, 42), + dateTime2ExprTs(today.plusDays(1).atTime(LocalTime.of(5, 50, 42)))), + Arguments.of(LocalTime.of(17, 30, 0), Instant.ofEpochSecond(42), + dateTime2ExprTs(today.atTime(LocalTime.of(17, 30, 42)))), + // DATETIME and STRING/DATE/TIME/DATETIME/TIMESTAMP + Arguments.of(LocalDateTime.of(1961, 4, 12, 9, 7, 0), "2077-12-15 01:48:00", + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of(LocalDateTime.of(1984, 2, 10, 12, 20, 42), LocalDate.of(2077, 12, 21), + dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), + Arguments.of(LocalDateTime.of(1961, 4, 12, 9, 7, 0), LocalTime.of(1, 48), + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of(LocalDateTime.of(2020, 12, 31, 17, 30, 0), + LocalDateTime.of(2077, 12, 21, 12, 20, 42), + dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), + Arguments.of(LocalDateTime.of(2020, 12, 31, 17, 30, 0), Instant.ofEpochSecond(42), + dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))), + // TIMESTAMP and STRING/DATE/TIME/DATETIME/TIMESTAMP + Arguments.of(dateTime2Instant(LocalDateTime.of(1961, 4, 12, 9, 7, 0)), + "2077-12-15 01:48:00", + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of(dateTime2Instant(LocalDateTime.of(1984, 2, 10, 12, 20, 42)), + LocalDate.of(2077, 12, 21), + dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), + Arguments.of(dateTime2Instant(LocalDateTime.of(1961, 4, 12, 9, 7, 0)), + LocalTime.of(1, 48), + dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), + Arguments.of(dateTime2Instant(LocalDateTime.of(2020, 12, 31, 17, 30, 0)), + LocalDateTime.of(2077, 12, 21, 12, 20, 42), + dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), + Arguments.of(dateTime2Instant(LocalDateTime.of(2020, 12, 31, 17, 30, 0)), + Instant.ofEpochSecond(42), + dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))) + ); + } + + @ParameterizedTest + @MethodSource("getTestData") + public void timestamp_with_two_args(Object arg1, Object arg2, ExprTimestampValue expected) { + var expr = dsl.timestamp( + DSL.literal(ExprValueUtils.fromObjectValue(arg1)), + DSL.literal(ExprValueUtils.fromObjectValue(arg2))); + assertEquals(TIMESTAMP, expr.type()); + assertEquals(expected, expr.valueOf(env)); + } +} From 5e6423b54b7fdf9dc88c6b3402923d71d6dbe79b Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 20 Oct 2022 15:45:37 -0700 Subject: [PATCH 08/14] Update docs. Signed-off-by: Yury-Fridlyand --- docs/user/dql/functions.rst | 28 +++--- docs/user/ppl/functions/datetime.rst | 133 ++++----------------------- 2 files changed, 33 insertions(+), 128 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 3e363efb820..f094fba48d5 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1172,9 +1172,9 @@ Argument type: DATETIME/STRING Return type map: -DATETIME, STRING -> DATETIME +(DATETIME, STRING) -> DATETIME -DATETIME -> DATETIME +(DATETIME) -> DATETIME Example:: @@ -2087,6 +2087,7 @@ Example:: | 2007-02-28 13:39:40 | +-----------------------------------------+ + TIME ---- @@ -2139,21 +2140,26 @@ TIMESTAMP Description >>>>>>>>>>> -Usage: timestamp(expr) construct a timestamp type with the input string expr as an timestamp. If the argument is of date/datetime/timestamp type, cast expr to timestamp type with default timezone UTC. +Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applied to today's date before cast. +With two arguments `timestamp(expr1, expr2)` adds the time expression `expr2` to the date or datetime expression `expr1` and returns the result as a timestamp value. -Argument type: STRING/DATE/DATETIME/TIMESTAMP +Argument type: STRING/DATE/TIME/DATETIME/TIMESTAMP + +Return type map: -Return type: TIMESTAMP +(STRING/DATE/TIME/DATETIME/TIMESTAMP) -> TIMESTAMP + +(STRING/DATE/TIME/DATETIME/TIMESTAMP, STRING/DATE/TIME/DATETIME/TIMESTAMP) -> TIMESTAMP Example:: - >od SELECT TIMESTAMP('2020-08-26 13:49:00') + os> SELECT TIMESTAMP('2020-08-26 13:49:00'), TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42')) fetched rows / total rows = 1/1 - +------------------------------------+ - | TIMESTAMP('2020-08-26 13:49:00') | - |------------------------------------| - | TIMESTAMP '2020-08-26 13:49:00 | - +------------------------------------+ + +------------------------------------+------------------------------------------------------+ + | TIMESTAMP('2020-08-26 13:49:00') | TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42')) | + |------------------------------------+------------------------------------------------------| + | 2020-08-26 13:49:00 | 2020-08-27 02:04:42 | + +------------------------------------+------------------------------------------------------+ TO_DAYS diff --git a/docs/user/ppl/functions/datetime.rst b/docs/user/ppl/functions/datetime.rst index ae893a5e8b0..a66e8c4efbb 100644 --- a/docs/user/ppl/functions/datetime.rst +++ b/docs/user/ppl/functions/datetime.rst @@ -234,111 +234,6 @@ Example:: +-------------------------------------------------------+ -CURDATE -------- - -Description ->>>>>>>>>>> - -Returns the current time as a value in 'YYYY-MM-DD'. -CURDATE() returns the time at which it executes as `SYSDATE() <#sysdate>`_ does. - -Return type: DATE - -Specification: CURDATE() -> DATE - -Example:: - - > source=people | eval `CURDATE()` = CURDATE() | fields `CURDATE()` - fetched rows / total rows = 1/1 - +-------------+ - | CURDATE() | - |-------------| - | 2022-08-02 | - +-------------+ - - -CURRENT_DATE ------------- - -Description ->>>>>>>>>>> - -`CURRENT_DATE()` are synonyms for `CURDATE() <#curdate>`_. - -Example:: - - > source=people | eval `CURRENT_DATE()` = CURRENT_DATE() | fields `CURRENT_DATE()` - fetched rows / total rows = 1/1 - +------------------+ - | CURRENT_DATE() | - |------------------+ - | 2022-08-02 | - +------------------+ - - -CURRENT_TIME ------------- - -Description ->>>>>>>>>>> - -`CURRENT_TIME()` are synonyms for `CURTIME() <#curtime>`_. - -Example:: - - > source=people | eval `CURRENT_TIME()` = CURRENT_TIME() | fields `CURRENT_TIME()` - fetched rows / total rows = 1/1 - +------------------+ - | CURRENT_TIME() | - |------------------+ - | 15:39:05 | - +------------------+ - - -CURRENT_TIMESTAMP ------------------ - -Description ->>>>>>>>>>> - -`CURRENT_TIMESTAMP()` are synonyms for `NOW() <#now>`_. - -Example:: - - > source=people | eval `CURRENT_TIMESTAMP()` = CURRENT_TIMESTAMP() | fields `CURRENT_TIMESTAMP()` - fetched rows / total rows = 1/1 - +-----------------------+ - | CURRENT_TIMESTAMP() | - |-----------------------+ - | 2022-08-02 15:54:19 | - +-----------------------+ - - -CURTIME -------- - -Description ->>>>>>>>>>> - -Returns the current time as a value in 'hh:mm:ss'. -CURTIME() returns the time at which the statement began to execute as `NOW() <#now>`_ does. - -Return type: TIME - -Specification: CURTIME() -> TIME - -Example:: - - > source=people | eval `value_1` = CURTIME(), `value_2` = CURTIME() | fields `value_1`, `value_2` - fetched rows / total rows = 1/1 - +-----------+-----------+ - | value_1 | value_2 | - |-----------+-----------| - | 15:39:05 | 15:39:05 | - +-----------+-----------+ - - DATE ---- @@ -516,7 +411,6 @@ Example:: +-----------------------------------------------+----------------------------------------------------------------+ - DATETIME -------- @@ -529,9 +423,9 @@ Argument type: DATETIME/STRING Return type map: -DATETIME, STRING -> DATETIME +(DATETIME, STRING) -> DATETIME -DATETIME -> DATETIME +(DATETIME) -> DATETIME Converting datetime with timezone to the second argument timezone. @@ -1281,21 +1175,26 @@ TIMESTAMP Description >>>>>>>>>>> -Usage: timestamp(expr) construct a timestamp type with the input string expr as an timestamp. If the argument is of date/datetime/timestamp type, cast expr to timestamp type with default timezone UTC. +Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applied to today's date before cast. +With two arguments `timestamp(expr1, expr2)` adds the time expression `expr2` to the date or datetime expression `expr1` and returns the result as a timestamp value. -Argument type: STRING/DATE/DATETIME/TIMESTAMP +Argument type: STRING/DATE/TIME/DATETIME/TIMESTAMP + +Return type map: + +(STRING/DATE/TIME/DATETIME/TIMESTAMP) -> TIMESTAMP -Return type: TIMESTAMP +(STRING/DATE/TIME/DATETIME/TIMESTAMP, STRING/DATE/TIME/DATETIME/TIMESTAMP) -> TIMESTAMP Example:: - >od source=people | eval `TIMESTAMP('2020-08-26 13:49:00')` = TIMESTAMP('2020-08-26 13:49:00') | fields `TIMESTAMP('2020-08-26 13:49:00')` + os> source=people | eval `TIMESTAMP('2020-08-26 13:49:00')` = TIMESTAMP('2020-08-26 13:49:00'), `TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42'))` = TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42')) | fields `TIMESTAMP('2020-08-26 13:49:00')`, `TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42'))` fetched rows / total rows = 1/1 - +------------------------------------+ - | TIMESTAMP('2020-08-26 13:49:00') | - |------------------------------------| - | TIMESTAMP '2020-08-26 13:49:00 | - +------------------------------------+ + +------------------------------------+------------------------------------------------------+ + | TIMESTAMP('2020-08-26 13:49:00') | TIMESTAMP('2020-08-26 13:49:00', TIME('12:15:42')) | + |------------------------------------+------------------------------------------------------| + | 2020-08-26 13:49:00 | 2020-08-27 02:04:42 | + +------------------------------------+------------------------------------------------------+ TO_DAYS From e257d5c4af1c7e5e0a7418dcec0906032368db68 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 20 Oct 2022 15:51:55 -0700 Subject: [PATCH 09/14] Minor checkstyle fixes. Signed-off-by: Yury-Fridlyand --- .../sql/expression/datetime/DateTimeFunction.java | 1 - .../opensearch/sql/expression/datetime/TimestampTest.java | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index 16c193ecbe7..c9c92b511a0 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -599,7 +599,6 @@ private DefaultFunctionResolver time_to_sec() { /** * Extracts the timestamp of a date and time value. * Input strings may contain a timestamp only in format 'yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]' - * * STRING/DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP * STRING/DATE/TIME/DATETIME/TIMESTAMP, STRING/DATE/TIME/DATETIME/TIMESTAMP -> TIMESTAMP */ diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java index 68e7e59897c..66c9f345cfa 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java @@ -174,6 +174,12 @@ private static Stream getTestData() { ); } + /** + * Test `TIMESTAMP` function which takes 2 arguments with input of different types. + * @param arg1 First argument to be passed to `TIMESTAMP` function. + * @param arg2 Second argument to be passed to `TIMESTAMP` function. + * @param expected The expected result. + */ @ParameterizedTest @MethodSource("getTestData") public void timestamp_with_two_args(Object arg1, Object arg2, ExprTimestampValue expected) { From 5e8620203c86f2d5c9a45011ec9a1f093207e320 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 31 Oct 2022 18:42:24 -0700 Subject: [PATCH 10/14] Make function to throw an exception on incorrect input. Signed-off-by: Yury-Fridlyand --- .../expression/datetime/DateTimeFunction.java | 9 +---- .../expression/datetime/TimestampTest.java | 37 ++++++++++--------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index c9c92b511a0..d0b7ead496b 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -1187,14 +1187,9 @@ private ExprValue exprTime(ExprValue exprValue) { */ private ExprValue exprTimestamp(ExprValue exprValue) { if (exprValue instanceof ExprStringValue) { - try { - return new ExprTimestampValue(exprValue.stringValue()); - } catch (SemanticCheckException ignored) { - return ExprNullValue.of(); - } - } else { - return new ExprTimestampValue(exprValue.timestampValue()); + return new ExprTimestampValue(exprValue.stringValue()); } + return new ExprTimestampValue(exprValue.timestampValue()); } /** diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java index 66c9f345cfa..ad61ebd9956 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java @@ -6,6 +6,7 @@ package org.opensearch.sql.expression.datetime; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP; import java.time.Instant; @@ -17,13 +18,14 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.opensearch.sql.data.model.ExprNullValue; import org.opensearch.sql.data.model.ExprTimestampValue; import org.opensearch.sql.data.model.ExprValue; import org.opensearch.sql.data.model.ExprValueUtils; +import org.opensearch.sql.exception.SemanticCheckException; import org.opensearch.sql.expression.DSL; import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.ExpressionTestBase; @@ -47,22 +49,23 @@ public void timestamp_one_arg_string() { expr.valueOf(env).datetimeValue()); } - @Test - public void timestamp_one_arg_string_invalid_format() { - // Feb 30th - var expr = dsl.timestamp(DSL.literal("1984-02-30 12:20:42")); - assertEquals(TIMESTAMP, expr.type()); - assertEquals(ExprNullValue.of(), expr.valueOf(env)); - - // 24:00:00 - expr = dsl.timestamp(DSL.literal("1984-02-10 24:00:00")); - assertEquals(TIMESTAMP, expr.type()); - assertEquals(ExprNullValue.of(), expr.valueOf(env)); - - // 2 digit year - expr = dsl.timestamp(DSL.literal("84-02-10 12:20:42")); - assertEquals(TIMESTAMP, expr.type()); - assertEquals(ExprNullValue.of(), expr.valueOf(env)); + /** + * Check that `TIMESTAMP` function throws an exception on incorrect string input. + * @param value A value. + * @param testName A test name. + */ + @ParameterizedTest(name = "{1}") + @CsvSource({ + "1984-02-30 12:20:42, Feb 30th", + "1984-02-10 24:00:00, 24:00:00", + "84-02-10 12:20:42, 2 digit year" + }) + public void timestamp_one_arg_string_invalid_format(String value, String testName) { + // exception thrown from ExprTimestampValue(String) CTOR + var exception = assertThrows(SemanticCheckException.class, + () -> dsl.timestamp(DSL.literal(value)).valueOf(env)); + assertEquals(String.format("timestamp:%s in unsupported format, please " + + "use yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]", value), exception.getMessage()); } @Test From 86524aac8f053072ee105c76a93b72a7e7f18fff Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 12 Dec 2022 19:23:21 -0800 Subject: [PATCH 11/14] Fix rebasing errors. Signed-off-by: Yury-Fridlyand --- .../sql/data/model/ExprTimeValue.java | 17 ------ .../sql/data/model/DateTimeValueTest.java | 21 +++++-- .../expression/datetime/DateTimeTestBase.java | 28 +-------- .../sql/sql/DateTimeFunctionIT.java | 19 ++++++ ppl/src/main/antlr/OpenSearchPPLParser.g4 | 58 +++++++++++++++---- sql/src/main/antlr/OpenSearchSQLParser.g4 | 9 --- 6 files changed, 86 insertions(+), 66 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java b/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java index a1019acdbbb..d77a2615d26 100644 --- a/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java +++ b/core/src/main/java/org/opensearch/sql/data/model/ExprTimeValue.java @@ -13,9 +13,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Objects; import lombok.RequiredArgsConstructor; @@ -72,21 +70,6 @@ public Instant timestampValue(FunctionProperties functionProperties) { .toInstant(); } - @Override - public LocalDate dateValue() { - return LocalDate.now(); - } - - @Override - public LocalDateTime datetimeValue() { - return LocalDateTime.of(dateValue(), timeValue()); - } - - @Override - public Instant timestampValue() { - return ZonedDateTime.of(dateValue(), timeValue(), ZoneId.systemDefault()).toInstant(); - } - @Override public String toString() { return String.format("TIME '%s'", value()); diff --git a/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java b/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java index 4fc4a7d563f..a335478e193 100644 --- a/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java +++ b/core/src/test/java/org/opensearch/sql/data/model/DateTimeValueTest.java @@ -32,10 +32,23 @@ public void timeValueInterfaceTest() { assertEquals(TIME, timeValue.type()); assertEquals(LocalTime.parse("01:01:01"), timeValue.timeValue()); - assertEquals(LocalDate.now(), timeValue.dateValue()); - assertEquals(LocalDate.now().atTime(1, 1, 1), timeValue.datetimeValue()); - assertEquals(ZonedDateTime.of(LocalTime.parse("01:01:01").atDate(LocalDate.now()), - ZoneId.systemDefault()).toInstant(), timeValue.timestampValue()); + // It is prohibited to acquire values which include date part from `ExprTimeValue` + // without a FunctionProperties object + var exception = assertThrows(ExpressionEvaluationException.class, timeValue::dateValue); + assertEquals("invalid to get dateValue from value of type TIME", exception.getMessage()); + exception = assertThrows(ExpressionEvaluationException.class, timeValue::datetimeValue); + assertEquals("invalid to get datetimeValue from value of type TIME", exception.getMessage()); + exception = assertThrows(ExpressionEvaluationException.class, timeValue::timestampValue); + assertEquals("invalid to get timestampValue from value of type TIME", exception.getMessage()); + + var functionProperties = new FunctionProperties(); + var today = LocalDate.now(functionProperties.getQueryStartClock()); + + assertEquals(today, timeValue.dateValue(functionProperties)); + assertEquals(today.atTime(1, 1, 1), timeValue.datetimeValue(functionProperties)); + assertEquals(ZonedDateTime.of(LocalTime.parse("01:01:01").atDate(today), + ExprTimestampValue.ZONE).toInstant(), timeValue.timestampValue(functionProperties)); + assertEquals("01:01:01", timeValue.value()); assertEquals("TIME '01:01:01'", timeValue.toString()); exception = assertThrows(ExpressionEvaluationException.class, diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java index 08004a84dc4..38beaad1315 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeTestBase.java @@ -6,7 +6,6 @@ package org.opensearch.sql.expression.datetime; import static org.opensearch.sql.data.model.ExprValueUtils.fromObjectValue; -import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE; import java.time.Instant; import java.time.LocalDate; @@ -82,17 +81,6 @@ protected String fromUnixTime(Double value, String format) { .valueOf().stringValue(); } - protected FunctionExpression addtime(Expression date, Expression interval) { - var func = functionRepository.resolve(new FunctionSignature(new FunctionName("addtime"), - List.of(date.type(), interval.type()))); - return (FunctionExpression)func.apply(List.of(date, interval)); - } - - protected ExprValue addtime(Temporal first, Temporal second) { - return addtime(DSL.literal(fromObjectValue(first)), DSL.literal(fromObjectValue(second))) - .valueOf(null); - } - protected FunctionExpression maketime(Expression hour, Expression minute, Expression second) { return (FunctionExpression) functionRepository.compile( @@ -179,18 +167,8 @@ protected Double unixTimeStampOf(LocalDateTime value) { .valueOf().doubleValue(); } - protected FunctionExpression subtime(Expression date, Expression interval) { - var func = functionRepository.resolve(new FunctionSignature(new FunctionName("subtime"), - List.of(date.type(), interval.type()))); - return (FunctionExpression)func.apply(List.of(date, interval)); - } - - protected ExprValue subtime(Temporal first, Temporal second) { - return subtime(DSL.literal(fromObjectValue(first)), DSL.literal(fromObjectValue(second))) - .valueOf(null); - } - - protected ExprValue eval(Expression expression) { - return expression.valueOf(env); + protected Double unixTimeStampOf(Instant value) { + return unixTimeStampOf(DSL.literal(new ExprTimestampValue(value))) + .valueOf().doubleValue(); } } diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java index fd87a6d4e3f..f10596e21c3 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java @@ -826,6 +826,25 @@ public void testUnixTimeStamp() throws IOException { } @Test + public void testPeriodAdd() throws IOException { + var result = executeQuery( + "select PERIOD_ADD(200801, 2) as f1, PERIOD_ADD(200801, -12) as f2"); + verifySchema(result, + schema("PERIOD_ADD(200801, 2)", "f1", "integer"), + schema("PERIOD_ADD(200801, -12)", "f2", "integer")); + verifyDataRows(result, rows(200803, 200701)); + } + + @Test + public void testPeriodDiff() throws IOException { + var result = executeQuery( + "select PERIOD_DIFF(200802, 200703) as f1, PERIOD_DIFF(200802, 201003) as f2"); + verifySchema(result, + schema("PERIOD_DIFF(200802, 200703)", "f1", "integer"), + schema("PERIOD_DIFF(200802, 201003)", "f2", "integer")); + verifyDataRows(result, rows(11, -25)); + } + public void testAddTime() throws IOException { var result = executeQuery("SELECT" + " ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0`," diff --git a/ppl/src/main/antlr/OpenSearchPPLParser.g4 b/ppl/src/main/antlr/OpenSearchPPLParser.g4 index edc33983a4a..9cb539cfbaa 100644 --- a/ppl/src/main/antlr/OpenSearchPPLParser.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLParser.g4 @@ -428,17 +428,53 @@ trigonometricFunctionName ; dateAndTimeFunctionBase - : ADDDATE | ADDTIME | CONVERT_TZ | DATE | DATE_ADD | DATE_FORMAT | DATE_SUB - | DATETIME | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | FROM_UNIXTIME - | HOUR | MAKEDATE | MAKETIME | MICROSECOND | MINUTE | MONTH | MONTHNAME - | QUARTER | SECOND | SUBDATE | SUBTIME | SYSDATE | TIME | TIME_TO_SEC - | TIMESTAMP | TO_DAYS | UNIX_TIMESTAMP | WEEK | YEAR - ; - -// Functions which value could be cached in scope of a single query -constantFunctionName - : datetimeConstantLiteral - | CURDATE | CURTIME | NOW + : ADDDATE + | ADDTIME + | CONVERT_TZ + | CURRENT_DATE + | CURRENT_TIME + | CURRENT_TIMESTAMP + | DATE + | DATE_ADD + | DATE_FORMAT + | DATE_SUB + | DATETIME + | DAY + | DAYNAME + | DAYOFMONTH + | DAYOFWEEK + | DAYOFYEAR + | CURDATE + | CURTIME + | FROM_DAYS + | FROM_UNIXTIME + | HOUR + | LOCALTIME + | LOCALTIMESTAMP + | MAKEDATE + | MAKETIME + | MICROSECOND + | MINUTE + | MONTH + | MONTHNAME + | NOW + | PERIOD_ADD + | PERIOD_DIFF + | QUARTER + | SECOND + | SUBDATE + | SUBTIME + | SYSDATE + | TIME + | TIME_TO_SEC + | TIMESTAMP + | TO_DAYS + | UNIX_TIMESTAMP + | UTC_DATE + | UTC_TIME + | UTC_TIMESTAMP + | WEEK + | YEAR ; /** condition function return boolean value */ diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 3076727b55e..1598e7676cb 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -411,15 +411,6 @@ trigonometricFunctionName ; dateTimeFunctionName - : ADDDATE | ADDTIME | CONVERT_TZ | DATE | DATE_ADD | DATE_FORMAT | DATE_SUB - | DATETIME | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS | FROM_UNIXTIME - | HOUR | MAKEDATE | MAKETIME | MICROSECOND | MINUTE | MONTH | MONTHNAME - | QUARTER | SECOND | SUBDATE | SUBTIME | SYSDATE | TIME | TIME_TO_SEC - | TIMESTAMP | TO_DAYS | UNIX_TIMESTAMP | WEEK | YEAR - ; - -// Functions which value could be cached in scope of a single query -constantFunctionName : datetimeConstantLiteral | ADDDATE | ADDTIME From 84a1d4d868aab4090c45104a1e04dc28034b64ab Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 12 Dec 2022 19:30:34 -0800 Subject: [PATCH 12/14] Rework to use `FunctionProperties`. Signed-off-by: Yury-Fridlyand --- .../org/opensearch/sql/expression/DSL.java | 7 +- .../expression/datetime/DateTimeFunction.java | 243 +++++++++++------- .../opensearch/sql/utils/DateTimeUtils.java | 11 + .../expression/datetime/TimestampTest.java | 41 ++- docs/user/dql/functions.rst | 39 ++- docs/user/ppl/functions/datetime.rst | 144 ++++++++++- 6 files changed, 357 insertions(+), 128 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/DSL.java b/core/src/main/java/org/opensearch/sql/expression/DSL.java index f5fd1e33153..1373f46273e 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -387,7 +387,12 @@ public static FunctionExpression time_to_sec(Expression... expressions) { } public static FunctionExpression timestamp(Expression... expressions) { - return compile(FunctionProperties.None, BuiltinFunctionName.TIMESTAMP, expressions); + return timestamp(FunctionProperties.None, expressions); + } + + public static FunctionExpression timestamp(FunctionProperties functionProperties, + Expression... expressions) { + return compile(functionProperties, BuiltinFunctionName.TIMESTAMP, expressions); } public static FunctionExpression date_format(Expression... expressions) { diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index d0b7ead496b..f0d1f208810 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -128,6 +128,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(second()); repository.register(subdate()); repository.register(subtime()); + repository.register(sysdate()); repository.register(time()); repository.register(time_to_sec()); repository.register(timestamp()); @@ -249,22 +250,38 @@ private DefaultFunctionResolver adddate() { */ private DefaultFunctionResolver addtime() { return define(BuiltinFunctionName.ADDTIME.getName(), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), TIME, TIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATETIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, TIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, DATE), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, DATE, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, TIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, DATE), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprAddTime), DATETIME, TIMESTAMP, TIMESTAMP) + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + TIME, TIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + TIME, TIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + TIME, TIME, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + TIME, TIME, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATETIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATETIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATETIME, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATETIME, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATE, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATE, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATE, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, DATE, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, TIMESTAMP, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, TIMESTAMP, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, TIMESTAMP, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprAddTime), + DATETIME, TIMESTAMP, TIMESTAMP) ); } @@ -551,22 +568,38 @@ private DefaultFunctionResolver subdate() { */ private DefaultFunctionResolver subtime() { return define(BuiltinFunctionName.SUBTIME.getName(), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), TIME, TIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATETIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, DATE), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, DATE, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, TIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, DATE), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprSubTime), DATETIME, TIMESTAMP, TIMESTAMP) + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + TIME, TIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + TIME, TIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + TIME, TIME, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + TIME, TIME, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATETIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATETIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATETIME, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATETIME, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATE, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATE, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATE, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, DATE, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, TIMESTAMP, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, TIMESTAMP, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, TIMESTAMP, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprSubTime), + DATETIME, TIMESTAMP, TIMESTAMP) ); } @@ -604,39 +637,65 @@ private DefaultFunctionResolver time_to_sec() { */ private DefaultFunctionResolver timestamp() { return define(BuiltinFunctionName.TIMESTAMP.getName(), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestamp), TIMESTAMP, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, STRING, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATE, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestamp), + TIMESTAMP, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestamp), + TIMESTAMP, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestamp), + TIMESTAMP, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestamp), + TIMESTAMP, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestamp), + TIMESTAMP, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, STRING, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, STRING, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, STRING, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, STRING, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, STRING, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATE, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATE, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATE, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATE, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATE, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIME, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIME, DATETIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIME, TIMESTAMP), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATETIME, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATETIME, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, DATETIME, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), TIMESTAMP, DATETIME, TIMESTAMP), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, STRING), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATE), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIMESTAMP, STRING), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIMESTAMP, DATE), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), + TIMESTAMP, TIMESTAMP, TIME), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, DATETIME), - impl(nullMissingHandling(DateTimeFunction::exprTimestampEx), + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprTimestampEx), TIMESTAMP, TIMESTAMP, TIMESTAMP)); } @@ -740,36 +799,36 @@ private ExprValue exprAddDateDays(ExprValue date, ExprValue days) { /** * Adds or subtracts time to/from date and returns the result. * - * @param date A Date/Time/Datetime/Timestamp value to change. - * @param time A Date/Time/Datetime/Timestamp object to add/subtract time from. - * @param add A flag: true to add, false to subtract. + * @param functionProperties A FunctionProperties object. + * @param temporal A Date/Time/Datetime/Timestamp value to change. + * @param temporalDelta A Date/Time/Datetime/Timestamp object to add/subtract time from. + * @param isAdd A flag: true to add, false to subtract. * @return A value calculated. */ - private ExprValue exprApplyTime(ExprValue date, ExprValue time, Boolean add) { - var timeToAdd = time.type() == TIME - ? time.timeValue() - : time.datetimeValue().toLocalTime(); - var dt = date.type() == TIME - ? LocalDate.now().atTime(date.timeValue()) - : date.datetimeValue(); - var interval = Duration.between(LocalTime.MIN, timeToAdd); - dt = add ? dt.plus(interval) : dt.minus(interval); - return date.type() == TIME - ? new ExprTimeValue(dt.toLocalTime()) - : new ExprDatetimeValue(dt); + private ExprValue exprApplyTime(FunctionProperties functionProperties, + ExprValue temporal, ExprValue temporalDelta, Boolean isAdd) { + var interval = Duration.between(LocalTime.MIN, temporalDelta.timeValue()); + var result = isAdd + ? extractDateTime(temporal, functionProperties).plus(interval) + : extractDateTime(temporal, functionProperties).minus(interval); + return temporal.type() == TIME + ? new ExprTimeValue(result.toLocalTime()) + : new ExprDatetimeValue(result); } /** * Adds time to date and returns the result. * - * @param date A Date/Time/Datetime/Timestamp value to change. - * @param time A Date/Time/Datetime/Timestamp object to add time from. + * @param functionProperties A FunctionProperties object. + * @param temporal A Date/Time/Datetime/Timestamp value to change. + * @param temporalDelta A Date/Time/Datetime/Timestamp object to add time from. * @return A value calculated. */ - private ExprValue exprAddTime(ExprValue date, ExprValue time) { - return exprApplyTime(date, time, true); + private ExprValue exprAddTime(FunctionProperties functionProperties, + ExprValue temporal, ExprValue temporalDelta) { + return exprApplyTime(functionProperties, temporal, temporalDelta, true); } - + /** * CONVERT_TZ function implementation for ExprValue. * Returns null for time zones outside of +13:00 and -12:00. @@ -1157,12 +1216,13 @@ private ExprValue exprSubDateInterval(ExprValue date, ExprValue expr) { /** * Subtracts expr2 from expr1 and returns the result. * - * @param date A Date/Time/Datetime/Timestamp value to change. - * @param time A Date/Time/Datetime/Timestamp to subtract time from. + * @param temporal A Date/Time/Datetime/Timestamp value to change. + * @param temporalDelta A Date/Time/Datetime/Timestamp to subtract time from. * @return A value calculated. */ - private ExprValue exprSubTime(ExprValue date, ExprValue time) { - return exprApplyTime(date, time, false); + private ExprValue exprSubTime(FunctionProperties functionProperties, + ExprValue temporal, ExprValue temporalDelta) { + return exprApplyTime(functionProperties, temporal, temporalDelta, false); } /** @@ -1185,11 +1245,11 @@ private ExprValue exprTime(ExprValue exprValue) { * @param exprValue ExprValue of Timestamp. * @return ExprValue. */ - private ExprValue exprTimestamp(ExprValue exprValue) { + private ExprValue exprTimestamp(FunctionProperties functionProperties, ExprValue exprValue) { if (exprValue instanceof ExprStringValue) { return new ExprTimestampValue(exprValue.stringValue()); } - return new ExprTimestampValue(exprValue.timestampValue()); + return new ExprTimestampValue(DateTimeUtils.extractTimestamp(exprValue, functionProperties)); } /** @@ -1200,8 +1260,11 @@ private ExprValue exprTimestamp(ExprValue exprValue) { * @param exprValue2 ExprValue of Timestamp type or String type. * @return ExprValue. */ - private ExprValue exprTimestampEx(ExprValue exprValue1, ExprValue exprValue2) { - return exprAddTime(exprTimestamp(exprValue1), exprTimestamp(exprValue2)); + private ExprValue exprTimestampEx(FunctionProperties functionProperties, + ExprValue exprValue1, ExprValue exprValue2) { + return exprAddTime(functionProperties, + exprTimestamp(functionProperties, exprValue1), + exprTimestamp(functionProperties, exprValue2)); } /** diff --git a/core/src/main/java/org/opensearch/sql/utils/DateTimeUtils.java b/core/src/main/java/org/opensearch/sql/utils/DateTimeUtils.java index 6ca9486de61..0f8a81fd372 100644 --- a/core/src/main/java/org/opensearch/sql/utils/DateTimeUtils.java +++ b/core/src/main/java/org/opensearch/sql/utils/DateTimeUtils.java @@ -139,4 +139,15 @@ public static LocalDateTime extractDateTime(ExprValue value, ? ((ExprTimeValue) value).datetimeValue(functionProperties) : value.datetimeValue(); } + + /** + * Extracts Instant from a datetime ExprValue. + * Uses `FunctionProperties` for `ExprTimeValue`. + */ + public static Instant extractTimestamp(ExprValue value, + FunctionProperties functionProperties) { + return value instanceof ExprTimeValue + ? ((ExprTimeValue) value).timestampValue(functionProperties) + : value.timestampValue(); + } } diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java index ad61ebd9956..98c4332b17c 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java @@ -15,38 +15,28 @@ import java.time.LocalTime; import java.util.stream.Stream; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import org.opensearch.sql.data.model.ExprTimestampValue; -import org.opensearch.sql.data.model.ExprValue; import org.opensearch.sql.data.model.ExprValueUtils; import org.opensearch.sql.exception.SemanticCheckException; import org.opensearch.sql.expression.DSL; -import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.ExpressionTestBase; -import org.opensearch.sql.expression.env.Environment; -@ExtendWith(MockitoExtension.class) public class TimestampTest extends ExpressionTestBase { - @Mock - Environment env; - @Test public void timestamp_one_arg_string() { - var expr = dsl.timestamp(DSL.literal("1961-04-12 09:07:00")); + var expr = DSL.timestamp(functionProperties, DSL.literal("1961-04-12 09:07:00")); assertEquals(TIMESTAMP, expr.type()); - assertEquals(new ExprTimestampValue("1961-04-12 09:07:00"), expr.valueOf(env)); + assertEquals(new ExprTimestampValue("1961-04-12 09:07:00"), expr.valueOf()); - expr = dsl.timestamp(DSL.literal("1961-04-12 09:07:00.123456")); + expr = DSL.timestamp(functionProperties, DSL.literal("1961-04-12 09:07:00.123456")); assertEquals(TIMESTAMP, expr.type()); assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0, 123456000), - expr.valueOf(env).datetimeValue()); + expr.valueOf().datetimeValue()); } /** @@ -63,42 +53,43 @@ public void timestamp_one_arg_string() { public void timestamp_one_arg_string_invalid_format(String value, String testName) { // exception thrown from ExprTimestampValue(String) CTOR var exception = assertThrows(SemanticCheckException.class, - () -> dsl.timestamp(DSL.literal(value)).valueOf(env)); + () -> DSL.timestamp(functionProperties, DSL.literal(value)).valueOf()); assertEquals(String.format("timestamp:%s in unsupported format, please " + "use yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]", value), exception.getMessage()); } @Test public void timestamp_one_arg_time() { - var expr = dsl.timestamp(dsl.time(DSL.literal("22:33:44"))); + var expr = DSL.timestamp(functionProperties, DSL.time(DSL.literal("22:33:44"))); assertEquals(TIMESTAMP, expr.type()); var refValue = LocalDate.now().atTime(LocalTime.of(22, 33, 44)) .atZone(ExprTimestampValue.ZONE).toInstant(); - assertEquals(new ExprTimestampValue(refValue), expr.valueOf(env)); + assertEquals(new ExprTimestampValue(refValue), expr.valueOf()); } @Test public void timestamp_one_arg_date() { - var expr = dsl.timestamp(dsl.date(DSL.literal("2077-12-15"))); + var expr = DSL.timestamp(functionProperties, DSL.date(DSL.literal("2077-12-15"))); assertEquals(TIMESTAMP, expr.type()); var refValue = LocalDate.of(2077, 12, 15).atStartOfDay() .atZone(ExprTimestampValue.ZONE).toInstant(); - assertEquals(new ExprTimestampValue(refValue), expr.valueOf(env)); + assertEquals(new ExprTimestampValue(refValue), expr.valueOf()); } @Test public void timestamp_one_arg_datetime() { - var expr = dsl.timestamp(dsl.datetime(DSL.literal("1961-04-12 09:07:00"))); + var expr = DSL.timestamp(functionProperties, DSL.datetime(DSL.literal("1961-04-12 09:07:00"))); assertEquals(TIMESTAMP, expr.type()); - assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0), expr.valueOf(env).datetimeValue()); + assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0), expr.valueOf().datetimeValue()); } @Test public void timestamp_one_arg_timestamp() { var refValue = new ExprTimestampValue(Instant.ofEpochSecond(10050042)); - var expr = dsl.timestamp(dsl.timestamp(DSL.literal(refValue))); + var expr = DSL.timestamp(functionProperties, + DSL.timestamp(functionProperties, DSL.literal(refValue))); assertEquals(TIMESTAMP, expr.type()); - assertEquals(refValue, expr.valueOf(env)); + assertEquals(refValue, expr.valueOf()); } private static Instant dateTime2Instant(LocalDateTime dt) { @@ -186,10 +177,10 @@ private static Stream getTestData() { @ParameterizedTest @MethodSource("getTestData") public void timestamp_with_two_args(Object arg1, Object arg2, ExprTimestampValue expected) { - var expr = dsl.timestamp( + var expr = DSL.timestamp(functionProperties, DSL.literal(ExprValueUtils.fromObjectValue(arg1)), DSL.literal(ExprValueUtils.fromObjectValue(arg2))); assertEquals(TIMESTAMP, expr.type()); - assertEquals(expected, expr.valueOf(env)); + assertEquals(expected, expr.valueOf()); } } diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index f094fba48d5..bbc3794557f 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -893,7 +893,7 @@ Antonyms: `SUBTIME`_ Example:: - os> SELECT ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) AS `'23:59:59' + 0` + os> SELECT ADDTIME(DATE('2008-12-12'), DATE('2008-11-15')) AS `'2008-12-12' + 0 ` fetched rows / total rows = 1/1 +---------------------+ | '2008-12-12' + 0 | @@ -2081,11 +2081,38 @@ Example:: os> SELECT SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) AS `'2007-03-01 10:20:30' - '20:40:50'` fetched rows / total rows = 1/1 - +-----------------------------------------+ - | `'2007-03-01 10:20:30' - '20:40:50'` | - |-----------------------------------------| - | 2007-02-28 13:39:40 | - +-----------------------------------------+ + +--------------------------------------+ + | '2007-03-01 10:20:30' - '20:40:50' | + |--------------------------------------| + | 2007-02-28 13:39:40 | + +--------------------------------------+ + + +SYSDATE +------- + +Description +>>>>>>>>>>> + +Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss[.nnnnnn]'. +SYSDATE() returns the time at which it executes. This differs from the behavior for `NOW() <#now>`_, which returns a constant time that indicates the time at which the statement began to execute. +If the argument is given, it specifies a fractional seconds precision from 0 to 6, the return value includes a fractional seconds part of that many digits. + +Optional argument type: INTEGER + +Return type: DATETIME + +Specification: SYSDATE([INTEGER]) -> DATETIME + +Example:: + + > SELECT SYSDATE() as value_1, SYSDATE(6) as value_2; + fetched rows / total rows = 1/1 + +---------------------+----------------------------+ + | value_1 | value_2 | + |---------------------+----------------------------| + | 2022-08-02 15:39:05 | 2022-08-02 15:39:05.123456 | + +---------------------+----------------------------+ TIME diff --git a/docs/user/ppl/functions/datetime.rst b/docs/user/ppl/functions/datetime.rst index a66e8c4efbb..7a4875c20cb 100644 --- a/docs/user/ppl/functions/datetime.rst +++ b/docs/user/ppl/functions/datetime.rst @@ -67,7 +67,7 @@ Example:: | 2008-12-12 00:00:00 | +---------------------+ - os> source=people | `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' + 0` + os> source=people | eval `'23:59:59' + 0` = ADDTIME(TIME('23:59:59'), DATE('2004-01-01')) | fields `'23:59:59' + 0` fetched rows / total rows = 1/1 +------------------+ | '23:59:59' + 0 | @@ -234,6 +234,111 @@ Example:: +-------------------------------------------------------+ +CURDATE +------- + +Description +>>>>>>>>>>> + +Returns the current time as a value in 'YYYY-MM-DD'. +CURDATE() returns the time at which it executes as `SYSDATE() <#sysdate>`_ does. + +Return type: DATE + +Specification: CURDATE() -> DATE + +Example:: + + > source=people | eval `CURDATE()` = CURDATE() | fields `CURDATE()` + fetched rows / total rows = 1/1 + +-------------+ + | CURDATE() | + |-------------| + | 2022-08-02 | + +-------------+ + + +CURRENT_DATE +------------ + +Description +>>>>>>>>>>> + +`CURRENT_DATE()` are synonyms for `CURDATE() <#curdate>`_. + +Example:: + + > source=people | eval `CURRENT_DATE()` = CURRENT_DATE() | fields `CURRENT_DATE()` + fetched rows / total rows = 1/1 + +------------------+ + | CURRENT_DATE() | + |------------------+ + | 2022-08-02 | + +------------------+ + + +CURRENT_TIME +------------ + +Description +>>>>>>>>>>> + +`CURRENT_TIME()` are synonyms for `CURTIME() <#curtime>`_. + +Example:: + + > source=people | eval `CURRENT_TIME()` = CURRENT_TIME() | fields `CURRENT_TIME()` + fetched rows / total rows = 1/1 + +------------------+ + | CURRENT_TIME() | + |------------------+ + | 15:39:05 | + +------------------+ + + +CURRENT_TIMESTAMP +----------------- + +Description +>>>>>>>>>>> + +`CURRENT_TIMESTAMP()` are synonyms for `NOW() <#now>`_. + +Example:: + + > source=people | eval `CURRENT_TIMESTAMP()` = CURRENT_TIMESTAMP() | fields `CURRENT_TIMESTAMP()` + fetched rows / total rows = 1/1 + +-----------------------+ + | CURRENT_TIMESTAMP() | + |-----------------------+ + | 2022-08-02 15:54:19 | + +-----------------------+ + + +CURTIME +------- + +Description +>>>>>>>>>>> + +Returns the current time as a value in 'hh:mm:ss'. +CURTIME() returns the time at which the statement began to execute as `NOW() <#now>`_ does. + +Return type: TIME + +Specification: CURTIME() -> TIME + +Example:: + + > source=people | eval `value_1` = CURTIME(), `value_2` = CURTIME() | fields `value_1`, `value_2` + fetched rows / total rows = 1/1 + +-----------+-----------+ + | value_1 | value_2 | + |-----------+-----------| + | 15:39:05 | 15:39:05 | + +-----------+-----------+ + + DATE ---- @@ -1092,11 +1197,38 @@ Example:: os> source=people | eval `'2007-03-01 10:20:30' - '20:40:50'` = SUBTIME(TIMESTAMP('2007-03-01 10:20:30'), DATETIME('2002-03-04 20:40:50')) | fields `'2007-03-01 10:20:30' - '20:40:50'` fetched rows / total rows = 1/1 - +-----------------------------------------+ - | `'2007-03-01 10:20:30' - '20:40:50'` | - |-----------------------------------------| - | 2007-02-28 13:39:40 | - +-----------------------------------------+ + +--------------------------------------+ + | '2007-03-01 10:20:30' - '20:40:50' | + |--------------------------------------| + | 2007-02-28 13:39:40 | + +--------------------------------------+ + + +SYSDATE +------- + +Description +>>>>>>>>>>> + +Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss[.nnnnnn]'. +SYSDATE() returns the time at which it executes. This differs from the behavior for `NOW() <#now>`_, which returns a constant time that indicates the time at which the statement began to execute. +If the argument is given, it specifies a fractional seconds precision from 0 to 6, the return value includes a fractional seconds part of that many digits. + +Optional argument type: INTEGER + +Return type: DATETIME + +Specification: SYSDATE([INTEGER]) -> DATETIME + +Example:: + + > source=people | eval `value_1` = SYSDATE(), `value_2` = SYSDATE(6) | fields `value_1`, `value_2` + fetched rows / total rows = 1/1 + +---------------------+----------------------------+ + | value_1 | value_2 | + |---------------------+----------------------------| + | 2022-08-02 15:39:05 | 2022-08-02 15:39:05.123456 | + +---------------------+----------------------------+ TIME From 95ee90d664c51b7cdd827dadf4b764c43ea8bd5f Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 12 Dec 2022 19:34:13 -0800 Subject: [PATCH 13/14] Typo fix. Signed-off-by: Yury-Fridlyand --- .../opensearch/sql/expression/datetime/DateTimeFunction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index f0d1f208810..a2edbf03581 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -828,7 +828,7 @@ private ExprValue exprAddTime(FunctionProperties functionProperties, ExprValue temporal, ExprValue temporalDelta) { return exprApplyTime(functionProperties, temporal, temporalDelta, true); } - + /** * CONVERT_TZ function implementation for ExprValue. * Returns null for time zones outside of +13:00 and -12:00. From f938ea83796cefe60b15787cea67999798b2421c Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 15 Dec 2022 12:21:04 -0800 Subject: [PATCH 14/14] Apply suggestions from code review Signed-off-by: Yury-Fridlyand Co-authored-by: Andrew Carbonetto --- docs/user/dql/functions.rst | 2 +- docs/user/ppl/functions/datetime.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index bbc3794557f..9144ec420bf 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -2167,7 +2167,7 @@ TIMESTAMP Description >>>>>>>>>>> -Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applied to today's date before cast. +Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applies today's date before cast. With two arguments `timestamp(expr1, expr2)` adds the time expression `expr2` to the date or datetime expression `expr1` and returns the result as a timestamp value. Argument type: STRING/DATE/TIME/DATETIME/TIMESTAMP diff --git a/docs/user/ppl/functions/datetime.rst b/docs/user/ppl/functions/datetime.rst index 7a4875c20cb..cef46cd1844 100644 --- a/docs/user/ppl/functions/datetime.rst +++ b/docs/user/ppl/functions/datetime.rst @@ -1307,7 +1307,7 @@ TIMESTAMP Description >>>>>>>>>>> -Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applied to today's date before cast. +Usage: timestamp(expr) constructs a timestamp type with the input string `expr` as an timestamp. If the argument is not a string, it casts `expr` to timestamp type with default timezone UTC. If argument is a time, it applies today's date before cast. With two arguments `timestamp(expr1, expr2)` adds the time expression `expr2` to the date or datetime expression `expr1` and returns the result as a timestamp value. Argument type: STRING/DATE/TIME/DATETIME/TIMESTAMP