diff --git a/be/src/core/value/time_value.h b/be/src/core/value/time_value.h index 64efc49521af6e..cff47407e20209 100644 --- a/be/src/core/value/time_value.h +++ b/be/src/core/value/time_value.h @@ -64,9 +64,11 @@ class TimeValue { static TimeType make_time(int64_t hour, int64_t minute, int64_t second, int64_t microsecond = 0, bool negative = false) { if constexpr (CHECK) { - // the max time value is 838:59:59.999999 + // the max time value is 838:59:59.000000 if (std::abs(hour) > 838 || std::abs(minute) >= 60 || std::abs(second) >= 60 || - std::abs(microsecond) >= 1000000) [[unlikely]] { + std::abs(microsecond) >= 1000000 || + (std::abs(hour) == 838 && std::abs(minute) == 59 && std::abs(second) == 59 && + microsecond != 0)) [[unlikely]] { throw Exception(ErrorCode::INVALID_ARGUMENT, "Invalid time value: hour={}, minute={}, second={}, microsecond={}", hour, minute, second, microsecond); diff --git a/be/test/exprs/function/cast/cast_to_time_test.cpp b/be/test/exprs/function/cast/cast_to_time_test.cpp index f2129fb444cf57..afd4216bc62cae 100644 --- a/be/test/exprs/function/cast/cast_to_time_test.cpp +++ b/be/test/exprs/function/cast/cast_to_time_test.cpp @@ -40,6 +40,8 @@ TEST_F(FunctionCastTest, test_from_string_strict_mode_to_time) { {{std::string("5656.3000000009")}, std::string("00:56:56.300000")}, {{std::string("5656.3000007001")}, std::string("00:56:56.300001")}, {{std::string("12:34:56.123")}, std::string("12:34:56.123")}, + {{std::string("838:59:59.000000")}, std::string("838:59:59.000000")}, + {{std::string("-838:59:59.000000")}, std::string("-838:59:59.000000")}, }; check_function_for_cast_strict_mode(input_types, data_set, "", 6); } @@ -54,6 +56,8 @@ TEST_F(FunctionCastTest, test_from_string_strict_mode_to_time) { {{std::string("12:34:")}, Null()}, {{std::string("76")}, Null()}, {{std::string("200595912")}, Null()}, + {{std::string("838:59:59.999999")}, Null()}, + {{std::string("-838:59:59.999999")}, Null()}, {{std::string("8385959.9999999")}, Null()}, {{std::string(" 1 ")}, Null()}, }; @@ -80,6 +84,8 @@ TEST_F(FunctionCastTest, test_from_string_non_strict_mode_to_time) { {{std::string("5656.3000000009")}, std::string("00:56:56.300000")}, {{std::string("5656.3000007001")}, std::string("00:56:56.300001")}, {{std::string("12:34:56.123")}, std::string("12:34:56.123")}, + {{std::string("838:59:59.000000")}, std::string("838:59:59.000000")}, + {{std::string("-838:59:59.000000")}, std::string("-838:59:59.000000")}, {{std::string(" 1 ")}, std::string("00:00:01.000000")}, {{std::string(".123")}, Null()}, {{std::string(":12:34")}, Null()}, @@ -89,6 +95,8 @@ TEST_F(FunctionCastTest, test_from_string_non_strict_mode_to_time) { {{std::string("12:34:")}, Null()}, {{std::string("76")}, Null()}, {{std::string("200595912")}, Null()}, + {{std::string("838:59:59.999999")}, Null()}, + {{std::string("-838:59:59.999999")}, Null()}, {{std::string("8385959.9999999")}, Null()}, {{Null()}, Null()}, }; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java index cae0a989314fb7..98ad34b5e7931b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java @@ -751,7 +751,7 @@ public static Expression makeTime(BigIntLiteral hour, BigIntLiteral minute, Doub long totalMicrosecond = Math.abs(hourValue) * 3600L * 1000000 + minuteValue * 60L * 1000000 + Math.round(secondValue * 1000000); - long maxMicrosecond = 838L * 3600L * 1000000 + 59L * 60L * 1000000 + 59999999L; + long maxMicrosecond = 838L * 3600L * 1000000 + 59L * 60L * 1000000 + 59L * 1000000; totalMicrosecond = Math.min(totalMicrosecond, maxMicrosecond); int newHour = (int) (totalMicrosecond / 3600L / 1000000); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java index 8d04a006baf51a..d4c3f8be3e6a0e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java @@ -105,7 +105,7 @@ public TimeV2Literal(int hour, int minute, int second, int microsecond, int scal this.microsecond = (int) (microsecond / Math.pow(10, 6 - scale)) * (int) Math.pow(10, 6 - scale); this.negative = negative; if (checkRange(this.hour, this.minute, this.second, this.microsecond) || scale > 6 || scale < 0) { - throw new AnalysisException("time literal is out of range [-838:59:59.999999, 838:59:59.999999]"); + throw new AnalysisException("time literal is out of range [-838:59:59.000000, 838:59:59.000000]"); } } @@ -263,7 +263,7 @@ protected void init(String s) throws AnalysisException { protected static boolean checkRange(double hour, int minute, int second, int microsecond) { return hour > 838 || minute > 59 || second > 59 || microsecond > 999999 || minute < 0 || second < 0 - || microsecond < 0; + || microsecond < 0 || (hour == 838 && minute == 59 && second == 59 && microsecond != 0); } /** diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java index f32ca713dcd9cf..96bbf8929f8184 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java @@ -21,8 +21,10 @@ import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal; import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal; +import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.StringLiteral; +import org.apache.doris.nereids.trees.expressions.literal.TimeV2Literal; import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.types.DateTimeV2Type; @@ -34,6 +36,17 @@ import java.time.LocalDateTime; class DateTimeExtractAndTransformTest { + @Test + void testMakeTimeSaturatesAtMySqlEndpoint() { + TimeV2Literal positive = (TimeV2Literal) DateTimeExtractAndTransform.makeTime( + new BigIntLiteral(838), new BigIntLiteral(59), new DoubleLiteral(59.999999)); + TimeV2Literal negative = (TimeV2Literal) DateTimeExtractAndTransform.makeTime( + new BigIntLiteral(-838), new BigIntLiteral(59), new DoubleLiteral(59.999999)); + + Assertions.assertEquals("838:59:59.000000", positive.getStringValue()); + Assertions.assertEquals("-838:59:59.000000", negative.getStringValue()); + } + @Test void testSpecialDateWeeks() { // test week/yearweek for 0000-01-01/02 diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java index 96775d44bfc628..112145cd7122a1 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java @@ -69,25 +69,25 @@ public void testTimeV2LiteralCreate() { s = literal.getStringValue(); Assertions.assertEquals(s, "12:12:12.121212"); // max val - literal = new TimeV2Literal(TimeV2Type.of(6), "838:59:59.999999"); + literal = new TimeV2Literal(TimeV2Type.of(6), "838:59:59.000000"); s = literal.getStringValue(); - Assertions.assertEquals(s, "838:59:59.999999"); + Assertions.assertEquals(s, "838:59:59.000000"); // min val - literal = new TimeV2Literal(TimeV2Type.of(6), "-838:59:59.999999"); + literal = new TimeV2Literal(TimeV2Type.of(6), "-838:59:59.000000"); s = literal.getStringValue(); - Assertions.assertEquals(s, "-838:59:59.999999"); + Assertions.assertEquals(s, "-838:59:59.000000"); // not string literal = new TimeV2Literal(12, 12, 12, 121212, 6, false); s = literal.getStringValue(); Assertions.assertEquals(s, "12:12:12.121212"); // max val - literal = new TimeV2Literal(838, 59, 59, 999999, 6, false); + literal = new TimeV2Literal(838, 59, 59, 0, 6, false); s = literal.getStringValue(); - Assertions.assertEquals(s, "838:59:59.999999"); + Assertions.assertEquals(s, "838:59:59.000000"); // min val - literal = new TimeV2Literal(838, 59, 59, 999999, 6, true); + literal = new TimeV2Literal(838, 59, 59, 0, 6, true); s = literal.getStringValue(); - Assertions.assertEquals(s, "-838:59:59.999999"); + Assertions.assertEquals(s, "-838:59:59.000000"); // string without ":" literal = new TimeV2Literal(TimeV2Type.of(0), "8385959"); s = literal.getStringValue(); @@ -98,12 +98,12 @@ public void testTimeV2LiteralCreate() { literal = new TimeV2Literal(TimeV2Type.of(0), "120000"); s = literal.getStringValue(); Assertions.assertEquals(s, "12:00:00"); - literal = new TimeV2Literal(TimeV2Type.of(6), "8385959.999999"); + literal = new TimeV2Literal(TimeV2Type.of(6), "8385959.000000"); s = literal.getStringValue(); - Assertions.assertEquals(s, "838:59:59.999999"); - literal = new TimeV2Literal(TimeV2Type.of(6), "-8385959.999999"); + Assertions.assertEquals(s, "838:59:59.000000"); + literal = new TimeV2Literal(TimeV2Type.of(6), "-8385959.000000"); s = literal.getStringValue(); - Assertions.assertEquals(s, "-838:59:59.999999"); + Assertions.assertEquals(s, "-838:59:59.000000"); // one ":" literal = new TimeV2Literal(TimeV2Type.of(0), "12:00"); s = literal.getStringValue(); @@ -112,6 +112,10 @@ public void testTimeV2LiteralCreate() { @Test public void testTimeV2LiteralOutOfRange() { + Assertions.assertThrows(AnalysisException.class, + () -> new TimeV2Literal(TimeV2Type.of(6), "838:59:59.000001")); + Assertions.assertThrows(AnalysisException.class, + () -> new TimeV2Literal(TimeV2Type.of(6), "-838:59:59.000001")); Assertions.assertThrows(AnalysisException.class, () -> { new TimeV2Literal(838, 59, 59, 1000000, 6, false); });