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

csding18 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 58ff21b648e [Enhancement](function) The date_add function supports 
SECOND_MICROSECOND as interval type (#58665)
58ff21b648e is described below

commit 58ff21b648ee68c537ea7cdbc5d6d9a785127931
Author: csding <[email protected]>
AuthorDate: Fri Dec 5 16:44:55 2025 +0800

    [Enhancement](function) The date_add function supports SECOND_MICROSECOND 
as interval type (#58665)
    
    The date_add function supports new type: SECOND_MICROSECOND, now we can
    use a string in the format 'second.microsecond' as the INTERVAL
    parameter.
    
    ```
    mysql>  select date_add("2025-10-10", INTERVAL "-1.-1" SECOND_MICROSECOND);
    +-------------------------------------------------------------+
    | date_add("2025-10-10", INTERVAL "-1.-1" SECOND_MICROSECOND) |
    +-------------------------------------------------------------+
    | 2025-10-09 23:59:58.900000                                  |
    +-------------------------------------------------------------+
    ```
---
 .../function_date_or_datetime_computation.cpp      |  3 +
 .../function_date_or_datetime_computation.h        | 74 ++++++++++++++++++++
 be/test/vec/function/function_time_test.cpp        | 35 ++++++++++
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  1 +
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  2 +-
 .../rules/analysis/DatetimeFunctionBinder.java     |  3 +
 .../functions/executable/DateTimeArithmetic.java   |  8 +++
 .../functions/scalar/SecondMicrosecondAdd.java     | 81 ++++++++++++++++++++++
 .../expressions/literal/DateTimeV2Literal.java     | 42 +++++++++++
 .../trees/expressions/literal/Interval.java        |  1 +
 .../expressions/visitor/ScalarFunctionVisitor.java |  5 ++
 .../nereids/rules/expression/FoldConstantTest.java | 17 +++++
 .../test_dateadd_with_other_timeunit.out           | 76 ++++++++++++++++++--
 .../test_dateadd_with_other_timeunit.groovy        | 65 ++++++++++++++++-
 14 files changed, 404 insertions(+), 9 deletions(-)

diff --git a/be/src/vec/functions/function_date_or_datetime_computation.cpp 
b/be/src/vec/functions/function_date_or_datetime_computation.cpp
index 2719b43254a..266324f28d6 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.cpp
+++ b/be/src/vec/functions/function_date_or_datetime_computation.cpp
@@ -96,6 +96,8 @@ using FunctionDatetimeAddDayHour =
         FunctionDateOrDateTimeComputation<AddDayHourImpl<TYPE_DATETIMEV2>>;
 using FunctionDatetimeAddMinuteSecond =
         
FunctionDateOrDateTimeComputation<AddMinuteSecondImpl<TYPE_DATETIMEV2>>;
+using FunctionDatetimeAddSecondMicrosecond =
+        
FunctionDateOrDateTimeComputation<AddSecondMicrosecondImpl<TYPE_DATETIMEV2>>;
 using FunctionDatetimeSubMicroseconds =
         
FunctionDateOrDateTimeComputation<SubtractMicrosecondsImpl<TYPE_DATETIMEV2>>;
 using FunctionDatetimeSubMilliseconds =
@@ -198,6 +200,7 @@ void 
register_function_date_time_computation(SimpleFunctionFactory& factory) {
     factory.register_function<FunctionDatetimeAddDaySecond>();
     factory.register_function<FunctionDatetimeAddDayHour>();
     factory.register_function<FunctionDatetimeAddMinuteSecond>();
+    factory.register_function<FunctionDatetimeAddSecondMicrosecond>();
 
     factory.register_function<FunctionSubDays>();
     factory.register_function<FunctionSubMonths>();
diff --git a/be/src/vec/functions/function_date_or_datetime_computation.h 
b/be/src/vec/functions/function_date_or_datetime_computation.h
index 03c95ed46fc..71137aefb6e 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.h
+++ b/be/src/vec/functions/function_date_or_datetime_computation.h
@@ -19,6 +19,7 @@
 
 #include <algorithm>
 #include <boost/iterator/iterator_facade.hpp>
+#include <cmath>
 #include <cstddef>
 #include <cstdint>
 #include <memory>
@@ -352,6 +353,79 @@ struct AddMinuteSecondImpl {
     }
 };
 
+template <PrimitiveType PType>
+struct AddSecondMicrosecondImpl {
+    static constexpr PrimitiveType ArgPType = PType;
+    static constexpr PrimitiveType ReturnType = PType;
+    static constexpr PrimitiveType IntervalPType = PrimitiveType ::TYPE_STRING;
+    using InputNativeType = typename PrimitiveTypeTraits<PType>::DataType 
::FieldType;
+    using ReturnNativeType = InputNativeType;
+    using IntervalDataType = typename 
PrimitiveTypeTraits<IntervalPType>::DataType;
+    using IntervalNativeType = IntervalDataType::FieldType; // string
+    using ConvertedType = typename 
PrimitiveTypeTraits<TYPE_BIGINT>::DataType::FieldType;
+
+    static constexpr auto name = "second_microsecond_add";
+    static constexpr auto is_nullable = false;
+
+    static inline ReturnNativeType execute(const InputNativeType& t, 
IntervalNativeType delta) {
+        long microseconds = 
parse_second_microsecond_string_to_microseconds(delta);
+        return date_time_add<TimeUnit::MICROSECOND, PType, ConvertedType>(t, 
microseconds);
+    }
+
+    static DataTypes get_variadic_argument_types() {
+        return {std ::make_shared<typename 
PrimitiveTypeTraits<PType>::DataType>(),
+                std ::make_shared<typename 
PrimitiveTypeTraits<IntervalPType>::DataType>()};
+    }
+
+    static long 
parse_second_microsecond_string_to_microseconds(IntervalNativeType 
time_str_ref) {
+        bool is_negative = false;
+        auto time_str = StringRef {time_str_ref.data(), 
time_str_ref.length()}.trim();
+        // string format: "s.microsecond"
+        size_t colon_pos = time_str.find_first_of('.');
+        if (colon_pos == std::string::npos) {
+            throw Exception(ErrorCode::INVALID_ARGUMENT,
+                            "Invalid time format, missing colon in '{}'",
+                            std::string_view {time_str.data, time_str.size});
+        }
+        // second
+        StringRef seconds_sub = time_str.substring(0, colon_pos).trim();
+        StringParser::ParseResult success;
+        int seconds = StringParser::string_to_int_internal<int32_t, true>(
+                seconds_sub.data, seconds_sub.size, &success);
+        if (success != StringParser::PARSE_SUCCESS) {
+            throw Exception(ErrorCode::INVALID_ARGUMENT, "Invalid seconds 
format in '{}'",
+                            std::string_view {time_str.data, time_str.size});
+        }
+        if (seconds < 0) {
+            is_negative = true;
+        }
+
+        // microsecond
+        StringRef microsecond_sub = time_str.substring(colon_pos + 1).trim();
+        auto microseconds = StringParser::string_to_int_internal<int64_t, 
true>(
+                microsecond_sub.data, microsecond_sub.size, &success);
+        if (success != StringParser::PARSE_SUCCESS) {
+            throw Exception(ErrorCode::INVALID_ARGUMENT, "Invalid microseconds 
format in '{}'",
+                            std::string_view {time_str.data, time_str.size});
+        }
+
+        long part0 = seconds;
+        // NOTE: Compatible with MySQL
+        int microsecond_len = microsecond_sub.to_string().starts_with("-")
+                                      ? microsecond_sub.size - 1
+                                      : microsecond_sub.size;
+        if (microsecond_len < 6) {
+            microseconds *= pow(10, 6 - microsecond_len);
+        }
+        long part1 = std::abs(microseconds);
+
+        if (is_negative) {
+            part1 *= -1;
+        }
+        return part0 * 1000000 + part1;
+    }
+};
+
 template <PrimitiveType PType>
 struct AddQuartersImpl {
     static constexpr PrimitiveType ArgPType = PType;
diff --git a/be/test/vec/function/function_time_test.cpp 
b/be/test/vec/function/function_time_test.cpp
index a211fb7b227..6c6bc58458f 100644
--- a/be/test/vec/function/function_time_test.cpp
+++ b/be/test/vec/function/function_time_test.cpp
@@ -1230,6 +1230,41 @@ TEST(VTimestampFunctionsTest, minute_second_add_v2_test) 
{
     }
 }
 
+TEST(VTimestampFunctionsTest, second_microsecond_add_v2_test) {
+    std::string func_name = "second_microsecond_add";
+
+    InputTypeSet input_types = {{PrimitiveType::TYPE_DATETIMEV2, 6},
+                                Consted {PrimitiveType::TYPE_STRING}};
+
+    {
+        DataSet data_set = {
+                {{std::string("2020-10-23 00:00:11.123456"), 
std::string("1.1")},
+                 std::string("2020-10-23 00:00:12.223456")},
+        };
+
+        static_cast<void>(
+                check_function<DataTypeDateTimeV2, true>(func_name, 
input_types, data_set, 6));
+    }
+    {
+        DataSet data_set = {
+                {{std::string("2020-05-23 00:00:11.123456"), 
std::string("1.12")},
+                 std::string("2020-05-23 00:00:12.243456")},
+        };
+
+        static_cast<void>(
+                check_function<DataTypeDateTimeV2, true>(func_name, 
input_types, data_set, 6));
+    }
+    {
+        DataSet data_set = {
+                {{std::string("2020-05-23 00:00:11.123456"), 
std::string("1.123")},
+                 std::string("2020-05-23 00:00:12.246456")},
+        };
+
+        static_cast<void>(
+                check_function<DataTypeDateTimeV2, true>(func_name, 
input_types, data_set, 6));
+    }
+}
+
 TEST(VTimestampFunctionsTest, to_days_v2_test) {
     std::string func_name = "to_days";
 
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index 490fa43cf9a..2bdc4110140 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -485,6 +485,7 @@ SCHEDULER: 'SCHEDULER';
 SCHEMA: 'SCHEMA';
 SCHEMAS: 'SCHEMAS';
 SECOND: 'SECOND';
+SECOND_MICROSECOND: 'SECOND_MICROSECOND';
 SELECT: 'SELECT';
 SEMI: 'SEMI';
 SEPARATOR: 'SEPARATOR';
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index 003f9c36b34..f8159777457 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -1773,7 +1773,7 @@ interval
 
 unitIdentifier
        : YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND | 
DAY_SECOND | DAY_HOUR
-    | MINUTE_SECOND
+    | MINUTE_SECOND | SECOND_MICROSECOND
     ;
 
 dataTypeWithNullable
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
index 474b9f3a0a7..9adc0e92bb0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
@@ -61,6 +61,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersDiff;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.SecondMicrosecondAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
@@ -308,6 +309,8 @@ public class DatetimeFunctionBinder {
                 return new DayHourAdd(timestamp, amount);
             case MINUTE_SECOND:
                 return new MinuteSecondAdd(timestamp, amount);
+            case SECOND_MICROSECOND:
+                return new SecondMicrosecondAdd(timestamp, amount);
             default:
                 throw new AnalysisException("Unsupported time stamp add time 
unit: " + unit
                         + ", supported time unit: 
YEAR/QUARTER/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java
index d3647a87220..797a98a0015 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java
@@ -62,6 +62,14 @@ public class DateTimeArithmetic {
         return date.plusMinuteSecond(minuteSecond);
     }
 
+    /**
+     * datetime arithmetic function second_microsecond-add.
+     */
+    @ExecFunction(name = "second_microsecond_add")
+    public static Expression secondMicrosecondAdd(DateTimeV2Literal date, 
VarcharLiteral secondMicrosecond) {
+        return date.plusSecondMicrosecond(secondMicrosecond);
+    }
+
     /**
      * datetime arithmetic function date-sub.
      */
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondMicrosecondAdd.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondMicrosecondAdd.java
new file mode 100644
index 00000000000..0474b404fef
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondMicrosecondAdd.java
@@ -0,0 +1,81 @@
+// 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.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import 
org.apache.doris.nereids.trees.expressions.functions.ComputeSignatureForDateArithmetic;
+import 
org.apache.doris.nereids.trees.expressions.functions.DateAddSubMonotonic;
+import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.VarcharType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'second_microsecond_add'.
+ */
+public class SecondMicrosecondAdd extends ScalarFunction
+        implements BinaryExpression, ExplicitlyCastableSignature,
+        ComputeSignatureForDateArithmetic, PropagateNullable, 
DateAddSubMonotonic {
+    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(DateTimeV2Type.MAX).args(DateTimeV2Type.MAX,
+            VarcharType.SYSTEM_DEFAULT));
+
+    public SecondMicrosecondAdd(Expression arg0, Expression arg1) {
+        super("second_microsecond_add", arg0, arg1);
+    }
+
+    /** constructor for withChildren and reuse signature */
+    private SecondMicrosecondAdd(ScalarFunctionParams functionParams) {
+        super(functionParams);
+    }
+
+    @Override
+    public SecondMicrosecondAdd withChildren(List<Expression> children) {
+        Preconditions.checkArgument(children.size() == 2);
+        return new SecondMicrosecondAdd(getFunctionParams(children));
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        return SIGNATURES;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitSecondMicrosecondAdd(this, context);
+    }
+
+    @Override
+    public Expression withConstantArgs(Expression literal) {
+        return new SecondMicrosecondAdd(literal, child(1));
+    }
+
+    @Override
+    public FunctionSignature computeSignature(FunctionSignature signature) {
+        signature = super.computeSignature(signature);
+        return signature.withArgumentType(0, 
DateTimeV2Type.MAX).withReturnType(DateTimeV2Type.MAX);
+    }
+}
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 8fd73a69e31..d149a04633c 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
@@ -364,6 +364,48 @@ public class DateTimeV2Literal extends DateTimeLiteral {
         }
     }
 
+    /**
+     * plusSecondMicrosecond
+     */
+    public Expression plusSecondMicrosecond(VarcharLiteral secondMicrosecond) {
+        String stringValue = secondMicrosecond.getStringValue().trim();
+
+        if (!stringValue.matches("[0-9\\-\\.\\s]+")) {
+            throw new NotSupportedException("Invalid time format");
+        }
+
+        String[] split = stringValue.split("\\.");
+        if (split.length != 2) {
+            throw new NotSupportedException("Invalid time format");
+        }
+
+        String second = split[0].trim();
+        String microsecond = split[1].trim();
+
+        try {
+            long seconds = Long.parseLong(second);
+            boolean secondPositive = seconds >= 0;
+
+            long microseconds = Long.parseLong(microsecond);
+            int microsecondLen = microsecond.startsWith("-") ? 
microsecond.length() - 1 : microsecond.length();
+            if (microsecondLen < 6) {
+                microseconds *= Math.pow(10, 6 - microsecondLen);
+            }
+
+            if (secondPositive) {
+                microseconds = Math.abs(microseconds);
+            } else {
+                microseconds = -Math.abs(microseconds);
+            }
+
+            return fromJavaDateType(toJavaDateType()
+                .plusSeconds(seconds)
+                .plusNanos(Math.multiplyExact(microseconds, 1000L)), 
getDataType().getScale());
+        } catch (NumberFormatException e) {
+            throw new NotSupportedException("Invalid time format");
+        }
+    }
+
     // When performing addition or subtraction with MicroSeconds, the 
precision must be set to 6 to display it
     // completely. use multiplyExact to be aware of multiplication overflow 
possibility.
     public Expression plusMicroSeconds(long microSeconds) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
index 28de8fc3e7b..385ca195684 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
@@ -83,6 +83,7 @@ public class Interval extends Expression implements 
UnaryExpression, AlwaysNotNu
      * Supported time unit.
      */
     public enum TimeUnit {
+        SECOND_MICROSECOND("SECOND_MICROSECOND", false, 1200),
         MINUTE_SECOND("MINUTE_SECOND", false, 1100),
         DAY_HOUR("DAY_HOUR", false, 1000),
         DAY_SECOND("DAY_SECOND", false, 900),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index 1999161c61e..baf5afb2b46 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -424,6 +424,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.Sec;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Second;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.SecondMicrosecondAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
@@ -1158,6 +1159,10 @@ public interface ScalarFunctionVisitor<R, C> {
         return visitScalarFunction(minuteSecondAdd, context);
     }
 
+    default R visitSecondMicrosecondAdd(SecondMicrosecondAdd 
secondMicrosecondAdd, C context) {
+        return visitScalarFunction(secondMicrosecondAdd, context);
+    }
+
     default R visitDaysAdd(DaysAdd daysAdd, C context) {
         return visitScalarFunction(daysAdd, context);
     }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
index a68a1eaedcf..e35312aa1f3 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
@@ -91,6 +91,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ReplaceEmpty;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Right;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Round;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Sec;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.SecondMicrosecondAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin;
@@ -467,6 +468,22 @@ class FoldConstantTest extends ExpressionRewriteTestHelper 
{
                 new VarcharLiteral("-2:-1"));
         rewritten = executor.rewrite(minuteSecondAdd, context);
         Assertions.assertEquals(minuteSecondAdd, rewritten);
+
+        SecondMicrosecondAdd secondMicrosecondAdd = new SecondMicrosecondAdd(
+                DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 
1, 1, 1), 6),
+                new VarcharLiteral("1.123456"));
+        rewritten = executor.rewrite(secondMicrosecondAdd, context);
+        Assertions.assertEquals(new DateTimeV2Literal("0001-01-01 
01:01:02.123456"), rewritten);
+        // fail to fold, because the result is out of range
+        secondMicrosecondAdd = new SecondMicrosecondAdd(
+                    DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(9999, 
12, 31, 23, 59, 1), 6),
+                    new VarcharLiteral("59.123456"));
+        rewritten = executor.rewrite(secondMicrosecondAdd, context);
+        Assertions.assertEquals(secondMicrosecondAdd, rewritten);
+        secondMicrosecondAdd = new 
SecondMicrosecondAdd(DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(0, 1, 
1, 0, 1, 1), 6),
+                new VarcharLiteral("-600.123456"));
+        rewritten = executor.rewrite(secondMicrosecondAdd, context);
+        Assertions.assertEquals(secondMicrosecondAdd, rewritten);
     }
 
     @Test
diff --git 
a/regression-test/data/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.out
 
b/regression-test/data/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.out
index cf0676a342f..9032bc441f2 100644
--- 
a/regression-test/data/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.out
+++ 
b/regression-test/data/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.out
@@ -1,10 +1,10 @@
 -- This file is automatically generated. You should know what you did if you 
want to edit this
 -- !sql --
-2025-10-25T02:03:04.456700
+2025-10-25T02:03:04.123456
 2025-10-30T11:11:11
 
 -- !sql --
-2025-10-25T02:03:04.456700
+2025-10-25T02:03:04.123456
 2025-10-30T11:11:11
 
 -- !sql --
@@ -34,11 +34,11 @@
 2025-10-27T22:58:59
 
 -- !sql --
-2025-10-25T02:02:03.456700
+2025-10-25T02:02:03.123456
 2025-10-30T11:10:10
 
 -- !sql --
-2025-10-25T02:02:03.456700
+2025-10-25T02:02:03.123456
 2025-10-30T11:10:10
 
 -- !sql --
@@ -98,11 +98,11 @@
 2025-10-27T14:00
 
 -- !sql --
-2025-10-24T01:03:04.456700
+2025-10-24T01:03:04.123456
 2025-10-29T10:11:11
 
 -- !sql --
-2025-10-24T01:03:04.456700
+2025-10-24T01:03:04.123456
 2025-10-29T10:11:11
 
 -- !sql --
@@ -161,3 +161,67 @@
 -- !sql --
 2025-10-28T23:58:50
 
+-- !sql --
+2025-10-24T01:02:04.223456
+2025-10-29T10:10:11.100
+
+-- !sql --
+2025-10-24T01:04:07.546888
+2025-10-29T10:12:14.423432
+
+-- !sql --
+2025-10-23T23:59:58.900
+2025-10-28T23:59:58.900
+
+-- !sql --
+2025-10-23T20:52:45.786877
+2025-10-28T20:52:45.786877
+
+-- !sql --
+2025-10-29T10:10:11.100
+
+-- !sql --
+2025-10-29T10:10:11.100
+
+-- !sql --
+2025-10-29T10:10:11.132310
+
+-- !sql --
+2025-10-29T10:10:11.132310
+
+-- !sql --
+2025-10-29T10:10:08.900
+
+-- !sql --
+2025-10-29T10:10:08.900
+
+-- !sql --
+2025-10-29T10:10:07.765433
+
+-- !sql --
+2025-10-29T10:10:07.765433
+
+-- !sql --
+2025-10-29T00:00:01.100
+
+-- !sql --
+2025-10-29T00:00:01.100
+
+-- !sql --
+2025-10-29T00:00:01.120
+
+-- !sql --
+2025-10-29T00:00:01.120
+
+-- !sql --
+2025-10-28T23:59:58.900
+
+-- !sql --
+2025-10-28T23:59:58.900
+
+-- !sql --
+2025-10-28T23:59:57.765433
+
+-- !sql --
+2025-10-28T23:59:57.765433
+
diff --git 
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.groovy
 
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.groovy
index d64ce939461..cdff84f949b 100644
--- 
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.groovy
+++ 
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_dateadd_with_other_timeunit.groovy
@@ -23,7 +23,7 @@ suite("test_dateadd_with_other_timeunit") {
     sql """ DROP TABLE IF EXISTS ${tableName} """
     sql """
             CREATE TABLE IF NOT EXISTS ${tableName} (
-                test_datetime datetime(4) NULL COMMENT "",
+                test_datetime datetime(6) NULL COMMENT "",
                 test_date date NULL COMMENT ""
             ) ENGINE=OLAP
             DUPLICATE KEY(test_datetime)
@@ -35,7 +35,7 @@ suite("test_dateadd_with_other_timeunit") {
                 "storage_format" = "V2"
             )
         """
-    sql """ insert into ${tableName} values ("2025-10-29 10:10:10", 
"2025-10-29"), ("2025-10-24 01:02:03.4567", "2025-10-24"); """
+    sql """ insert into ${tableName} values ("2025-10-29 10:10:10", 
"2025-10-29"), ("2025-10-24 01:02:03.123456", "2025-10-24"); """
     
     // DAY_SECOND
     testFoldConst """ select date_add("2025-10-29 10:10:10", INTERVAL "1 
1:1:1" DAY_SECOND); """
@@ -233,4 +233,65 @@ suite("test_dateadd_with_other_timeunit") {
         exception "Invalid seconds format"
     }
 
+    // SECOND_MICROSECOND
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"1.1" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"-1.1" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"1.12" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"1.-12" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"-1.12" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"-1.-12" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"-1.12345678" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29 10:10:10.123456", INTERVAL 
"-1.12345678" SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "1.1" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "1.-1" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "1.12" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "1.-12" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "-1.1" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "-1.-1" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "-1.12" 
SECOND_MICROSECOND); """
+    testFoldConst """ select date_add("2025-10-29", INTERVAL "-1.-123443" 
SECOND_MICROSECOND); """
+
+    qt_sql """ select date_add(test_datetime, INTERVAL "1.1" 
SECOND_MICROSECOND) result from ${tableName}; """
+    qt_sql """ select date_add(test_datetime, INTERVAL "1.123423432" 
SECOND_MICROSECOND) result from ${tableName}; """
+
+    qt_sql """ select date_add(test_date, INTERVAL "-1.1" SECOND_MICROSECOND) 
result from ${tableName}; """
+    qt_sql """ select date_add(test_date, INTERVAL "-1.-11233213123" 
SECOND_MICROSECOND) result from ${tableName}; """
+
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "1.1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "1.-1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "1.13231" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "1.-13231" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "-1.1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "-1.-1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "-1.1234567" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29 10:10:10", INTERVAL "-1.-1234567" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "1.1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "1.-1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "1.12" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "1.-12" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "-1.1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "-1.-1" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "-1.1234567" 
SECOND_MICROSECOND); """
+    qt_sql """ select date_add("2025-10-29", INTERVAL "-1.-1234567" 
SECOND_MICROSECOND); """
+
+    test {
+        sql """ select date_add("2025-10-29 10:10:10", INTERVAL '1' 
SECOND_MICROSECOND) ; """
+        exception "Invalid time format"
+
+        sql """ select date_add("2025-10-29 10:10:10", INTERVAL 'xx.10' 
SECOND_MICROSECOND) ; """
+        exception "Invalid time format"
+
+        sql """ select date_add("2025-10-29 10:10:10", INTERVAL '1.xx' 
SECOND_MICROSECOND) ; """
+        exception "Invalid time format"
+
+        sql """ select date_add(test_datetime, INTERVAL '1' 
SECOND_MICROSECOND) result from ${tableName}; """
+        exception "Invalid time format"
+
+        sql """ select date_add(test_datetime, INTERVAL 'xx.10' 
SECOND_MICROSECOND) result from ${tableName}; """
+        exception "Invalid seconds format"
+
+        sql """ select date_add(test_datetime, INTERVAL '1.xx' 
SECOND_MICROSECOND) result from ${tableName}; """
+        exception "Invalid microseconds format"
+    }
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to