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

dataroaring 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 e8553f85d80 [fix](date_function) fix str_to_date function return wrong 
microsecond issue (#47325)
e8553f85d80 is described below

commit e8553f85d80562d092680a5dd74d81f1533124f8
Author: Yulei-Yang <yulei.yang0...@gmail.com>
AuthorDate: Thu Mar 20 14:35:37 2025 +0800

    [fix](date_function) fix str_to_date function return wrong microsecond 
issue (#47325)
    
    bp https://github.com/apache/doris/pull/47129
    
    fix such issue both in legacy & nereids planner
---
 .../org/apache/doris/analysis/DateLiteral.java     | 12 +++-
 .../apache/doris/analysis/FunctionCallExpr.java    |  6 +-
 .../executable/DateTimeExtractAndTransform.java    | 14 +++-
 .../expressions/functions/scalar/StrToDate.java    |  3 +-
 .../trees/expressions/literal/DateTimeLiteral.java |  7 --
 .../doris/analysis/ComparisonPredicateTest.java    |  4 +-
 .../expressions/literal/DateTimeLiteralTest.java   | 10 +--
 .../jdbc/test_oracle_jdbc_catalog.groovy           |  2 +-
 .../test_date_function_v2.groovy                   | 84 ++++++++++++++++++++++
 9 files changed, 122 insertions(+), 20 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
index b68f3fc83da..524ca7dd0ca 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
@@ -110,6 +110,7 @@ public class DateLiteral extends LiteralExpr {
     private static Map<String, Integer> WEEK_DAY_NAME_DICT = Maps.newHashMap();
     private static Set<Character> TIME_PART_SET = Sets.newHashSet();
     private static final int[] DAYS_IN_MONTH = new int[] {0, 31, 28, 31, 30, 
31, 30, 31, 31, 30, 31, 30, 31};
+    private static String MICRO_SECOND_FORMATTER = "%f";
     private static final int ALLOW_SPACE_MASK = 4 | 64;
     private static final int MAX_DATE_PARTS = 8;
     private static final int YY_PART_YEAR = 70;
@@ -685,7 +686,7 @@ public class DateLiteral extends LiteralExpr {
             int scale = ((ScalarType) type).getScalarScale();
             long scaledMicroseconds = (long) (microsecond / 
SCALE_FACTORS[scale]);
 
-            if (scaledMicroseconds != 0) {
+            if (scale > 0) {
                 dateTimeChars[19] = '.';
                 fillPaddedValue(dateTimeChars, 20, (int) scaledMicroseconds, 
scale);
                 return new String(dateTimeChars, 0, 20 + scale);
@@ -1000,6 +1001,10 @@ public class DateLiteral extends LiteralExpr {
         return format.chars().anyMatch(c -> TIME_PART_SET.contains((char) c));
     }
 
+    public static boolean hasMicroSecondPart(String format) {
+        return format.indexOf(MICRO_SECOND_FORMATTER) != -1;
+    }
+
     // Return the date stored in the dateliteral as pattern format.
     // eg : "%Y-%m-%d" or "%Y-%m-%d %H:%i:%s"
     public String dateFormat(String pattern) throws AnalysisException {
@@ -1542,6 +1547,9 @@ public class DateLiteral extends LiteralExpr {
                     case 'T':
                         partUsed |= timePart;
                         break;
+                    case 'f':
+                        partUsed |= fracPart;
+                        break;
                     default:
                         break;
                 }
@@ -1603,7 +1611,7 @@ public class DateLiteral extends LiteralExpr {
 
         // Compute timestamp type
         if ((partUsed & datePart) != 0) { // Ymd part only
-            if ((partUsed & fracPart) != 0) {
+            if (hasMicroSecondPart(format)) {
                 this.type = Type.DATETIMEV2_WITH_MAX_SCALAR;
             } else if ((partUsed & timePart) != 0) {
                 this.type = ScalarType.getDefaultDateType(Type.DATETIME);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
index a5fb20bcfbd..c111c6563f1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java
@@ -1978,7 +1978,11 @@ public class FunctionCallExpr extends Expr {
             Expr child1Result = getChild(1).getResultValue(false);
             if (child1Result instanceof StringLiteral) {
                 if (DateLiteral.hasTimePart(child1Result.getStringValue())) {
-                    this.type = Type.DATETIMEV2_WITH_MAX_SCALAR;
+                    if 
(DateLiteral.hasMicroSecondPart(child1Result.getStringValue())) {
+                        this.type = Type.DATETIMEV2_WITH_MAX_SCALAR;
+                    } else {
+                        this.type = Type.DEFAULT_DATETIMEV2;
+                    }
                 } else {
                     this.type = Type.DATEV2;
                 }
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 0a282281cd5..fef06d48182 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
@@ -17,6 +17,8 @@
 
 package org.apache.doris.nereids.trees.expressions.functions.executable;
 
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.catalog.Type;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.trees.expressions.ExecFunction;
 import org.apache.doris.nereids.trees.expressions.Expression;
@@ -30,6 +32,8 @@ import 
org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateType;
 import org.apache.doris.nereids.types.VarcharType;
 import org.apache.doris.nereids.util.DateUtils;
@@ -575,8 +579,16 @@ public class DateTimeExtractAndTransform {
     @ExecFunction(name = "str_to_date", argTypes = {"VARCHAR", "VARCHAR"}, 
returnType = "DATETIMEV2")
     public static Expression strToDate(VarcharLiteral str, VarcharLiteral 
format) {
         if 
(org.apache.doris.analysis.DateLiteral.hasTimePart(format.getStringValue())) {
-            return 
DateTimeV2Literal.fromJavaDateType(DateUtils.getTime(DateUtils.formatBuilder(format.getValue())
+            DataType returnType = 
DataType.fromCatalogType(ScalarType.getDefaultDateType(Type.DATETIME));
+            if (returnType instanceof DateTimeV2Type) {
+                boolean hasMicroPart = org.apache.doris.analysis.DateLiteral
+                        .hasMicroSecondPart(format.getStringValue());
+                return 
DateTimeV2Literal.fromJavaDateType(DateUtils.getTime(DateUtils.formatBuilder(format.getValue())
+                    .toFormatter(), str.getValue()), hasMicroPart ? 6 : 0);
+            } else {
+                return 
DateTimeLiteral.fromJavaDateType(DateUtils.getTime(DateUtils.formatBuilder(format.getValue())
                     .toFormatter(), str.getValue()));
+            }
         } else {
             return 
DateV2Literal.fromJavaDateType(DateUtils.getTime(DateUtils.formatBuilder(format.getValue())
                     .toFormatter(), str.getValue()));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
index 1fbf15586d5..d1242016b7a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
@@ -87,7 +87,8 @@ public class StrToDate extends ScalarFunction
         if (getArgument(1) instanceof StringLikeLiteral) {
             if (DateLiteral.hasTimePart(((StringLikeLiteral) 
getArgument(1)).getStringValue())) {
                 returnType = 
DataType.fromCatalogType(ScalarType.getDefaultDateType(Type.DATETIME));
-                if (returnType.isDateTimeV2Type()) {
+                if (returnType.isDateTimeV2Type()
+                        && DateLiteral.hasMicroSecondPart(((StringLikeLiteral) 
getArgument(1)).getStringValue())) {
                     returnType = 
DataType.fromCatalogType(Type.DATETIMEV2_WITH_MAX_SCALAR);
                 }
             } else {
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 3ceaae2f102..77e82c5327f 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
@@ -117,13 +117,6 @@ public class DateTimeLiteral extends DateLiteral {
             }
             scale++;
         }
-        // trim the tailing zero
-        for (int i = 19 + scale; i >= 19; i--) {
-            if (s.charAt(i) != '0') {
-                break;
-            }
-            scale--;
-        }
         return scale;
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/analysis/ComparisonPredicateTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/ComparisonPredicateTest.java
index 6824db14172..24e52eb75d3 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/analysis/ComparisonPredicateTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/ComparisonPredicateTest.java
@@ -159,7 +159,7 @@ public class ComparisonPredicateTest {
 
         Assert.assertEquals(dateTimeExpr, range1.upperEndpoint());
         Assert.assertEquals(dateTimeV2Expr1, range1.upperEndpoint());
-        Assert.assertEquals(dateTimeV2Expr2, range1.upperEndpoint());
+        Assert.assertNotEquals(dateTimeV2Expr2, range1.upperEndpoint());
         Assert.assertEquals(BoundType.CLOSED, range1.upperBoundType());
         Assert.assertFalse(range1.hasLowerBound());
 
@@ -167,6 +167,6 @@ public class ComparisonPredicateTest {
         Assert.assertEquals(dateTimeV2Expr1, range2.upperEndpoint());
         Assert.assertEquals(BoundType.CLOSED, range2.upperBoundType());
         Assert.assertFalse(range2.hasLowerBound());
-        Assert.assertEquals(dateTimeV2Expr2, range2.upperEndpoint());
+        Assert.assertNotEquals(dateTimeV2Expr2, range2.upperEndpoint());
     }
 }
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 e7606cca352..f9e19f17a59 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
@@ -93,9 +93,9 @@ class DateTimeLiteralTest {
     @Test
     void testDetermineScale() {
         int scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.0");
-        Assertions.assertEquals(0, scale);
+        Assertions.assertEquals(1, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.00000");
-        Assertions.assertEquals(0, scale);
+        Assertions.assertEquals(5, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.000001");
         Assertions.assertEquals(6, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.123456");
@@ -103,11 +103,11 @@ class DateTimeLiteralTest {
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.0001");
         Assertions.assertEquals(4, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.00010");
-        Assertions.assertEquals(4, scale);
+        Assertions.assertEquals(5, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.12010");
-        Assertions.assertEquals(4, scale);
+        Assertions.assertEquals(5, scale);
         scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.02010");
-        Assertions.assertEquals(4, scale);
+        Assertions.assertEquals(5, scale);
     }
 
     @Test
diff --git 
a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy 
b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy
index a954d056eb3..936eb7318d4 100644
--- 
a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy
+++ 
b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy
@@ -132,7 +132,7 @@ suite("test_oracle_jdbc_catalog", 
"p0,external,oracle,external_docker,external_d
         order_qt_date4  """ select * from TEST_DATE where (T1 > '2022-01-21 
00:00:00' and T1 < '2022-01-22 00:00:00') or (T1 > '2022-01-20 00:00:00' and T1 
< '2022-01-23 00:00:00'); """
         order_qt_date5  """ select * from TEST_DATE where T1 < '2022-01-22 
00:00:00' or T1 = '2022-01-21 05:23:01'; """
         order_qt_date6  """ select * from TEST_DATE where (T1 < '2022-01-22 
00:00:00' or T1 > '2022-01-20 00:00:00') and (T1 < '2022-01-23 00:00:00' or T1 
> '2022-01-19 00:00:00'); """
-        order_qt_date7  """select * from TEST_TIMESTAMP where T2 < 
str_to_date('2020-12-21 12:34:56', '%Y-%m-%d %H:%i:%s');"""
+        order_qt_date7  """select * from TEST_TIMESTAMP where T2 < 
str_to_date('2020-12-21 12:34:56', '%Y-%m-%d %H:%i:%s.%f');"""
 
         // test nvl
         explain {
diff --git 
a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
 
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
new file mode 100644
index 00000000000..8b24c9d9c3f
--- /dev/null
+++ 
b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_function_v2.groovy
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_date_function_v2") {
+    sql """
+    admin set frontend config ("enable_date_conversion"="true");
+    """
+    sql """SET enable_nereids_planner=true"""
+
+    def tableName = "test_date_function_v2"
+
+    sql """ DROP TABLE IF EXISTS ${tableName} """
+    sql """
+            CREATE TABLE IF NOT EXISTS ${tableName} (
+                `id` INT,
+                `name` varchar(32),
+                `dt` varchar(32)
+            ) ENGINE=OLAP
+            UNIQUE KEY(`id`)
+            DISTRIBUTED BY HASH(`id`) BUCKETS 1
+            PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+            )
+        """
+    sql """ insert into ${tableName} values (3, 'Carl','2024-12-29 10:11:12') 
"""
+    def result1 = try_sql """
+        select cast(str_to_date(dt, '%Y-%m-%d %H:%i:%s') as string) from 
${tableName};
+    """
+    assertEquals(result1[0][0], "2024-12-29 10:11:12");
+
+    def result2 = try_sql """
+        select cast(str_to_date(dt, '%Y-%m-%d %H:%i:%s.%f') as string) from 
${tableName};
+    """
+    assertEquals(result2[0][0], "2024-12-29 10:11:12.000000");
+
+    def result3 = try_sql """
+        select cast(str_to_date("2025-01-17 11:59:30", '%Y-%m-%d %H:%i:%s') as 
string);
+    """
+    assertEquals(result3[0][0], "2025-01-17 11:59:30");
+
+    def result4 = try_sql """
+        select cast(str_to_date("2025-01-17 11:59:30", '%Y-%m-%d %H:%i:%s.%f') 
as string);
+    """
+    assertEquals(result4[0][0], "2025-01-17 11:59:30.000000");
+
+    // test legacy planner
+    sql """SET enable_nereids_planner=false"""
+    def result5 = try_sql """
+        select cast(str_to_date(dt, '%Y-%m-%d %H:%i:%s') as string) from 
${tableName};
+    """
+    assertEquals(result5[0][0], "2024-12-29 10:11:12");
+
+    result5 = try_sql """
+        select cast(str_to_date(dt, '%Y-%m-%d %H:%i:%s.%f') as string) from 
${tableName};
+    """
+    assertEquals(result5[0][0], "2024-12-29 10:11:12.000000");
+
+    result5 = try_sql """
+        select cast(str_to_date('2025-01-17 11:59:30', '%Y-%m-%d %H:%i:%s') as 
string);
+    """
+    assertEquals(result5[0][0], "2025-01-17 11:59:30");
+
+    result5 = try_sql """
+        select cast(str_to_date('2025-01-17 11:59:30', '%Y-%m-%d %H:%i:%s.%f') 
as string);
+    """
+    assertEquals(result5[0][0], "2025-01-17 11:59:30.000000");
+
+
+    sql """ drop table ${tableName} """
+}


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

Reply via email to