This is an automated email from the ASF dual-hosted git repository.

jakevin pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new 35289ee2449 [enhance](Nereids): support more DateLiteral (#30876)
35289ee2449 is described below

commit 35289ee2449a10d01b528d071c1821753db86da3
Author: jakevin <jakevin...@gmail.com>
AuthorDate: Mon Feb 5 23:26:33 2024 +0800

    [enhance](Nereids): support more DateLiteral (#30876)
    
    * [enhance](Nereids): support DateLiteral with suffix space (#30583)
    
    (cherry picked from commit ab5bddba39c1e8fc0b07255b85dfbbc492d9ce80)
    
    * [enhancement](Nereids): datetime support microsecond overflow (#30744)
    
    (cherry picked from commit 3c6206355b79084927f1fe0117770988312c0683)
---
 .../trees/expressions/literal/DateLiteral.java     | 17 +++++++----
 .../trees/expressions/literal/DateTimeLiteral.java | 16 +++++++++-
 .../expressions/literal/DateTimeV2Literal.java     |  9 ++++--
 .../apache/doris/nereids/types/DateTimeV2Type.java |  5 +++-
 .../doris/nereids/util/DateTimeFormatterUtils.java |  5 ++--
 .../trees/expressions/literal/DateLiteralTest.java | 16 +++++-----
 .../expressions/literal/DateTimeLiteralTest.java   | 34 ++++++++++++++++++----
 .../nereids/util/DateTimeFormatterUtilsTest.java   |  4 +--
 8 files changed, 79 insertions(+), 27 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
index 9fbece96756..58c252b4b98 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
@@ -36,6 +36,7 @@ import java.time.Year;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
 import java.util.Set;
+import java.util.function.UnaryOperator;
 
 /**
  * Date literal in Nereids.
@@ -100,7 +101,7 @@ public class DateLiteral extends Literal {
 
     // normalize yymmdd -> yyyymmdd
     static String normalizeBasic(String s) {
-        java.util.function.UnaryOperator<String> normalizeTwoDigit = (input) 
-> {
+        UnaryOperator<String> normalizeTwoDigit = (input) -> {
             String yy = input.substring(0, 2);
             int year = Integer.parseInt(yy);
             if (year >= 0 && year <= 69) {
@@ -182,9 +183,9 @@ public class DateLiteral extends Literal {
         // normalize leading 0 for date and time
         // date and time contains 6 number part at most, so we just need 
normal 6 number part
         int partNumber = 0;
-        while (i < s.length()) {
+        while (i < s.length() && partNumber < 6) {
             char c = s.charAt(i);
-            if (Character.isDigit(c) && partNumber < 6) {
+            if (Character.isDigit(c)) {
                 // find consecutive digit
                 int j = i + 1;
                 while (j < s.length() && Character.isDigit(s.charAt(j))) {
@@ -233,11 +234,14 @@ public class DateLiteral extends Literal {
         }
 
         // parse MicroSecond
+        // Keep up to 7 digits at most, 7th digit is use for overflow.
         if (partNumber == 6 && i < s.length() && s.charAt(i) == '.') {
             sb.append(s.charAt(i));
             i += 1;
             while (i < s.length() && Character.isDigit(s.charAt(i))) {
-                sb.append(s.charAt(i));
+                if (i - 19 <= 7) {
+                    sb.append(s.charAt(i));
+                }
                 i += 1;
             }
         }
@@ -265,9 +269,12 @@ public class DateLiteral extends Literal {
         try {
             TemporalAccessor dateTime;
 
+            // remove suffix/prefix ' '
+            s = s.trim();
             // parse condition without '-' and ':'
             boolean containsPunctuation = false;
-            for (int i = 0; i < s.length(); i++) {
+            int len = Math.min(s.length(), 11);
+            for (int i = 0; i < len; i++) {
                 if (isPunctuation(s.charAt(i))) {
                     containsPunctuation = true;
                     break;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
index 36131db238f..3f96ef52e68 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
@@ -136,7 +136,6 @@ public class DateTimeLiteral extends DateLiteral {
         hour = DateUtils.getOrDefault(temporal, ChronoField.HOUR_OF_DAY);
         minute = DateUtils.getOrDefault(temporal, ChronoField.MINUTE_OF_HOUR);
         second = DateUtils.getOrDefault(temporal, 
ChronoField.SECOND_OF_MINUTE);
-        microSecond = DateUtils.getOrDefault(temporal, 
ChronoField.MICRO_OF_SECOND);
 
         ZoneId zoneId = temporal.query(TemporalQueries.zone());
         if (zoneId != null) {
@@ -153,6 +152,21 @@ public class DateTimeLiteral extends DateLiteral {
             }
         }
 
+        microSecond = DateUtils.getOrDefault(temporal, 
ChronoField.NANO_OF_SECOND) / 100L;
+        // Microseconds have 7 digits.
+        long sevenDigit = microSecond % 10;
+        microSecond = microSecond / 10;
+        if (sevenDigit >= 5 && this instanceof DateTimeV2Literal) {
+            DateTimeV2Literal result = (DateTimeV2Literal) 
((DateTimeV2Literal) this).plusMicroSeconds(1);
+            this.second = result.second;
+            this.minute = result.minute;
+            this.hour = result.hour;
+            this.day = result.day;
+            this.month = result.month;
+            this.year = result.year;
+            this.microSecond = result.microSecond;
+        }
+
         if (checkRange() || checkDate()) {
             throw new AnalysisException("datetime literal [" + s + "] is out 
of range");
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
index 7471fc829fc..a9447affddd 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
@@ -66,7 +66,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
 
         if (this.microSecond >= 1000000) {
             LocalDateTime localDateTime = 
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND,
-                            getStringValue()).plusSeconds(1);
+                    getStringValue()).plusSeconds(1);
             this.year = localDateTime.getYear();
             this.month = localDateTime.getMonthValue();
             this.day = localDateTime.getDayOfMonth();
@@ -77,6 +77,11 @@ public class DateTimeV2Literal extends DateTimeLiteral {
         }
     }
 
+    public String getFullMicroSecondValue() {
+        return String.format("%04d-%02d-%02d %02d:%02d:%02d.%06d",
+                year, month, day, hour, minute, second, microSecond);
+    }
+
     @Override
     public DateTimeV2Type getDataType() throws UnboundException {
         return (DateTimeV2Type) super.getDataType();
@@ -157,7 +162,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
 
     public Expression plusMicroSeconds(long microSeconds) {
         return fromJavaDateType(
-                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getFullMicroSecondValue())
                         .plusNanos(microSeconds * 1000L), 
getDataType().getScale());
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
index 77891ed3486..be2dc165886 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
@@ -85,10 +85,13 @@ public class DateTimeV2Type extends DateLikeType {
 
     /**
      * return proper type of datetimev2 for String
-     * may be we need to check for validity?
+     * maybe we need to check for validity?
      */
     public static DateTimeV2Type forTypeFromString(String s) {
         int scale = DateTimeLiteral.determineScale(s);
+        if (scale > MAX_SCALE) {
+            scale = MAX_SCALE;
+        }
         return DateTimeV2Type.of(scale);
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
index e88aabc018b..50d0f7169a5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
@@ -56,8 +56,9 @@ public class DateTimeFormatterUtils {
             .appendValue(ChronoField.HOUR_OF_DAY, 2)
             .appendLiteral(':').appendValue(ChronoField.MINUTE_OF_HOUR, 2)
             .appendLiteral(':').appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+            // microsecond maxWidth is 7, we may need 7th digit to judge 
overflow
             .appendOptional(new DateTimeFormatterBuilder()
-                    .appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, 
true).toFormatter())
+                    .appendFraction(ChronoField.NANO_OF_SECOND, 1, 7, 
true).toFormatter())
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
     // Time without delimiter: HHmmss[.microsecond]
     private static final DateTimeFormatter BASIC_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
@@ -65,7 +66,7 @@ public class DateTimeFormatterUtils {
             .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
             .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
             .appendOptional(new DateTimeFormatterBuilder()
-                    .appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, 
true).toFormatter())
+                    .appendFraction(ChronoField.NANO_OF_SECOND, 1, 7, 
true).toFormatter())
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
     // yyyymmdd
     private static final DateTimeFormatter BASIC_DATE_FORMATTER = new 
DateTimeFormatterBuilder()
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
index a87a177a1b3..3430676b14d 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
@@ -28,14 +28,6 @@ import java.util.function.Consumer;
 class DateLiteralTest {
     @Test
     void reject() {
-        // TODO: reject them.
-        // Now parse them as date + offset.
-        // PG parse them as date + offset, MySQL parse them as date + time 
(rubbish behavior!)
-        // So strange! reject these strange case.
-        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01-01"));
-        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01-1"));
-        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01+01"));
-        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01+1"));
         Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01 01:00:00.000000"));
         Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01 00:01:00.000000"));
         Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01 00:00:01.000000"));
@@ -212,6 +204,12 @@ class DateLiteralTest {
         new DateLiteral("2020.02.01 00.00.00");
         new DateTimeV2Literal("2020.02.01 00.00.00.1");
         new DateTimeV2Literal("2020.02.01 00.00.00.000001");
-        Assertions.assertThrows(AnalysisException.class, () -> new 
DateTimeV2Literal("2020.02.01 00.00.00.0000001"));
+        new DateTimeV2Literal("2020.02.01 00.00.00.0000001");
+    }
+
+    @Test
+    void testSuffixSpace() {
+        new DateLiteral("2016-07-02  ");
+        new DateLiteral("2016-07-02 00:00:00  ");
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
index 3cfaf485bf6..8c636e9eca4 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
@@ -41,13 +41,14 @@ class DateTimeLiteralTest {
             Assertions.assertEquals(1, datetime.day);
             Assertions.assertEquals(1, datetime.hour);
             Assertions.assertEquals(1, datetime.minute);
-            Assertions.assertEquals(1, datetime.second);
+            Assertions.assertEquals(2, datetime.second);
         };
 
-        assertFunc.accept(new DateTimeV2Literal("20220801010101"));
-        assertFunc.accept(new DateTimeV2Literal("20220801T010101"));
-        assertFunc.accept(new DateTimeV2Literal("220801010101"));
-        assertFunc.accept(new DateTimeV2Literal("220801T010101"));
+        assertFunc.accept(new DateTimeV2Literal("20220801010102"));
+        assertFunc.accept(new DateTimeV2Literal("20220801T010102"));
+        assertFunc.accept(new DateTimeV2Literal("220801010102"));
+        assertFunc.accept(new DateTimeV2Literal("220801T010102"));
+        assertFunc.accept(new DateTimeV2Literal("20220801010101.9999999"));
     }
 
     @Test
@@ -386,6 +387,29 @@ class DateTimeLiteralTest {
         // Testing with microsecond of length 6
         new DateTimeV2Literal("2016-07-02 01:01:01.123456");
         new DateTimeV2Literal("2016-7-02 01:01:01.123456");
+
+        // Testing with microsecond of length 7
+        DateTimeV2Literal literal = new DateTimeV2Literal("2016-07-02 
01:01:01.12345678");
+        Assertions.assertEquals(123457, literal.microSecond);
+
+        literal = new DateTimeV2Literal("2016-07-02 01:01:01.44444444");
+        Assertions.assertEquals(444444, literal.microSecond);
+
+        literal = new DateTimeV2Literal("2016-07-02 01:01:01.44444445");
+        Assertions.assertEquals(444444, literal.microSecond);
+
+        literal = new DateTimeV2Literal("2016-07-02 01:01:01.4444445");
+        Assertions.assertEquals(444445, literal.microSecond);
+
+        literal = new DateTimeV2Literal("2016-07-02 01:01:01.9999995");
+        Assertions.assertEquals(0, literal.microSecond);
+        Assertions.assertEquals(2, literal.second);
+
+        literal = new DateTimeV2Literal("2021-01-01 23:59:59.9999995");
+        Assertions.assertEquals(0, literal.microSecond);
+        Assertions.assertEquals(0, literal.second);
+        Assertions.assertEquals(0, literal.minute);
+        Assertions.assertEquals(0, literal.hour);
     }
 
     @Test
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
index 853c8e11b41..8437fdb0092 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
@@ -70,6 +70,8 @@ class DateTimeFormatterUtilsTest {
         assertDatePart(dateTime);
         dateTime = formatter.parse("20200219T010101.1");
         assertDatePart(dateTime);
+        dateTime = formatter.parse("20200219T010101.0000001");
+        assertDatePart(dateTime);
 
         // failed case
         DateTimeFormatter withT = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER;
@@ -77,11 +79,9 @@ class DateTimeFormatterUtilsTest {
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219010101."));
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219010101.0000001"));
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219T010101."));
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219T010101.0000001"));
         DateTimeFormatter withoutT = 
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T;
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219 010101"));
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219010101."));
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219010101.0000001"));
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219T010101."));
         Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219T010101.0000001"));
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to