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

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


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new f4ab08916f4 branch-4.0: [Enhancement](function) Support two args 
versions of TIMESTAMP #58554 (#60005)
f4ab08916f4 is described below

commit f4ab08916f47f74876086cd1be16bf43a234ec81
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Jan 19 11:26:37 2026 +0800

    branch-4.0: [Enhancement](function) Support two args versions of TIMESTAMP 
#58554 (#60005)
    
    Cherry-picked from #58554
    
    Co-authored-by: linrrarity <[email protected]>
---
 .../rules/expression/ExpressionNormalization.java  |  7 ++-
 .../rules/expression/ExpressionRuleType.java       |  1 +
 .../rules/expression/rules/TimestampToAddTime.java | 52 +++++++++++++++++
 .../expressions/functions/scalar/Timestamp.java    | 17 ++++--
 .../expression/rules/TimestampToAddTimeTest.java   | 66 ++++++++++++++++++++++
 .../sql-functions/doc_date_functions_test.out      | 13 +++++
 .../sql-functions/doc_date_functions_test.groovy   | 47 +++++++++++++++
 7 files changed, 197 insertions(+), 6 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
index c7a33ce680e..f20bcd54ecb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
@@ -35,6 +35,7 @@ import 
org.apache.doris.nereids.rules.expression.rules.SimplifyArithmeticRule;
 import org.apache.doris.nereids.rules.expression.rules.SimplifyCastRule;
 import org.apache.doris.nereids.rules.expression.rules.SimplifyNotExprRule;
 import 
org.apache.doris.nereids.rules.expression.rules.SupportJavaDateFormatter;
+import org.apache.doris.nereids.rules.expression.rules.TimestampToAddTime;
 import org.apache.doris.nereids.trees.expressions.Expression;
 
 import com.google.common.collect.ImmutableList;
@@ -47,8 +48,9 @@ import java.util.List;
 public class ExpressionNormalization extends ExpressionRewrite {
     // we should run supportJavaDateFormatter before foldConstantRule or be 
will fold
     // from_unixtime(timestamp, 'yyyyMMdd') to 'yyyyMMdd'
-    // specically note: LogToLn and ConcatWsMultiArrayToOne must  before 
FoldConstantRule,otherwise log will core when
-    // input single argument like log(100),and concat_ws will retuen a wrong 
result when input multi array
+    // specically note: LogToLn, ConcatWsMultiArrayToOne and 
TimestampToAddTime must before FoldConstantRule,
+    // otherwise log will core when input single argument like log(100), and 
concat_ws will return a wrong result
+    // when input multi array
     public static final List<ExpressionRewriteRule<ExpressionRewriteContext>> 
NORMALIZE_REWRITE_RULES
                 = ImmutableList.of(
             bottomUp(
@@ -61,6 +63,7 @@ public class ExpressionNormalization extends 
ExpressionRewrite {
                 SimplifyArithmeticRule.INSTANCE,
                 LogToLn.INSTANCE,
                 ConcatWsMultiArrayToOne.INSTANCE,
+                TimestampToAddTime.INSTANCE,
                 FoldConstantRule.INSTANCE,
                 SimplifyCastRule.INSTANCE,
                 DigitalMaskingConvert.INSTANCE,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
index 4eacc7f1faf..b8803095d81 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
@@ -58,6 +58,7 @@ public enum ExpressionRuleType {
     SIMPLIFY_SELF_COMPARISON,
     SUPPORT_JAVA_DATE_FORMATTER,
     NORMALIZE_STRUCT_ELEMENT,
+    TIMESTAMP_TO_ADD_TIME,
     TOPN_TO_MAX,
     ADD_SESSION_VAR_GUARD;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTime.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTime.java
new file mode 100644
index 00000000000..eadec87c95c
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTime.java
@@ -0,0 +1,52 @@
+// 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.rules.expression.rules;
+
+import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher;
+import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory;
+import org.apache.doris.nereids.rules.expression.ExpressionRuleType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.AddTime;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Timestamp;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * Convert two-argument TIMESTAMP function to ADD_TIME function.
+ */
+public class TimestampToAddTime implements ExpressionPatternRuleFactory {
+
+    public static final TimestampToAddTime INSTANCE = new TimestampToAddTime();
+
+    @Override
+    public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
+        return ImmutableList.of(
+                matchesType(Timestamp.class).then(TimestampToAddTime::rewrite)
+                        .toRule(ExpressionRuleType.TIMESTAMP_TO_ADD_TIME)
+        );
+    }
+
+    public static Expression rewrite(Timestamp timestamp) {
+        if (timestamp.arity() == 2) {
+            return new AddTime(timestamp.child(0), timestamp.child(1));
+        }
+        return timestamp;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Timestamp.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Timestamp.java
index e2d7b5280da..b79152982ea 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Timestamp.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Timestamp.java
@@ -21,9 +21,9 @@ import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
 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.UnaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeV2Type;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -34,12 +34,14 @@ import java.util.List;
  * ScalarFunction 'timestamp'. This class is generated by GenerateFunction.
  */
 public class Timestamp extends ScalarFunction
-        implements UnaryExpression, ExplicitlyCastableSignature, 
PropagateNullable {
+        implements ExplicitlyCastableSignature, PropagateNullable {
     // When enable_date_conversion is true, we prefer to V2 signature.
     // This preference follows original planner. refer to
     // ScalarType.getDefaultDateType()
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(DateTimeV2Type.WILDCARD).args(DateTimeV2Type.WILDCARD));
+            
FunctionSignature.ret(DateTimeV2Type.WILDCARD).args(DateTimeV2Type.WILDCARD),
+            
FunctionSignature.ret(DateTimeV2Type.WILDCARD).args(DateTimeV2Type.WILDCARD, 
TimeV2Type.WILDCARD)
+    );
 
     /**
      * constructor with 1 argument.
@@ -48,6 +50,13 @@ public class Timestamp extends ScalarFunction
         super("timestamp", arg);
     }
 
+    /**
+     * constructor with 2 argument.
+     */
+    public Timestamp(Expression arg0, Expression arg1) {
+        super("timestamp", arg0, arg1);
+    }
+
     /** constructor for withChildren and reuse signature */
     private Timestamp(ScalarFunctionParams functionParams) {
         super(functionParams);
@@ -58,7 +67,7 @@ public class Timestamp extends ScalarFunction
      */
     @Override
     public Timestamp withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 1);
+        Preconditions.checkArgument(children.size() == 1 || children.size() == 
2);
         return new Timestamp(getFunctionParams(children));
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTimeTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTimeTest.java
new file mode 100644
index 00000000000..ab8ae8d7722
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/TimestampToAddTimeTest.java
@@ -0,0 +1,66 @@
+// 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.rules.expression.rules;
+
+import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper;
+import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Test;
+
+class TimestampToAddTimeTest extends ExpressionRewriteTestHelper {
+    @Test
+    void testTwoArgumentTimestampToAddTime() {
+        executor = new ExpressionRuleExecutor(ImmutableList.of(
+                bottomUp(TimestampToAddTime.INSTANCE)
+        ));
+
+        assertRewriteAfterTypeCoercion(
+                "timestamp('2024-01-01 10:00:00', '01:30:00')",
+                "add_time('2024-01-01 10:00:00', '01:30:00')"
+        );
+        assertRewriteAfterTypeCoercion(
+                "timestamp(A, '01:30:00')",
+                "add_time(A, '01:30:00')"
+        );
+        assertRewriteAfterTypeCoercion(
+                "timestamp('2024-01-01 10:00:00', '00:00:00')",
+                "add_time('2024-01-01 10:00:00', '00:00:00')"
+        );
+    }
+
+    @Test
+    void testSingleArgumentTimestampUnchanged() {
+        executor = new ExpressionRuleExecutor(ImmutableList.of(
+                bottomUp(TimestampToAddTime.INSTANCE)
+        ));
+
+        assertRewriteAfterTypeCoercion(
+                "timestamp('2024-01-01 10:00:00')",
+                "timestamp('2024-01-01 10:00:00')"
+        );
+        assertRewriteAfterTypeCoercion(
+                "timestamp(A)",
+                "timestamp(A)"
+        );
+        assertRewriteAfterTypeCoercion(
+                "timestamp(C)",
+                "timestamp(C)"
+        );
+    }
+}
diff --git 
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out 
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
index a05c5e1a17b..cef8965836e 100644
--- 
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
+++ 
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
@@ -2032,6 +2032,19 @@ da fanadur
 \N
 07:23:25
 
+-- !timestamp_two_args_1 --
+2025-11-03T17:43:21    2025-11-01T13:36:59     \N      \N
+2025-01-03T17:43:21    2025-01-02T01:23:44     \N      \N
+2025-02-02T17:43:21    2025-02-01T01:23:44     \N      \N
+2026-01-02T17:43:21    2026-01-01T01:23:44     \N      \N
+\N     \N      \N      \N
+
+-- !timestamp_two_args_2 --
+\N
+
+-- !timestamp_two_args_3 --
+2026-01-05T16:30:44
+
 -- !time_format_1 --
 1      00:00:00        00      0       12      12      12      00      00      
00      000000  AM      12:00:00 AM     00:00:00        00:00:00.000000 0 00 12 
12 12   00 000000 00 AM 00:00:00 12:00:00 AM 12:12      12 0 12 00 12 AM        
000000 00 00 00:00:00 12:00:00 AM
 2      00:00:00.123456 00      0       12      12      12      00      00      
00      123456  AM      12:00:00 AM     00:00:00        00:00:00.123456 0 00 12 
12 12   00 123456 00 AM 00:00:00 12:00:00 AM 12:12      12 0 12 00 12 AM        
123456 00 00 00:00:00 12:00:00 AM
diff --git 
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
 
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
index d62a505a53d..ff2eb33b4f8 100644
--- 
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
+++ 
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
@@ -1399,6 +1399,39 @@ suite("doc_date_functions_test") {
     qt_maketime_test_1 """SELECT MAKETIME(hour,minute,sec) FROM maketime_test 
ORDER BY id;"""
     qt_maketime_test_2 """SELECT MAKETIME(hour, minute, 25) FROM maketime_test 
ORDER BY id;"""
 
+    //102. TIMESTAMP with two args Function test
+    sql """DROP TABLE IF EXISTS test_timestamp"""
+    sql """CREATE TABLE test_timestamp (
+            id INT,
+            dt DATE,
+            dttm DATETIME,
+        ) PROPERTIES ( 'replication_num' = '1' );"""
+    sql """INSERT INTO test_timestamp VALUES
+            (1, '2025-11-01', '2025-11-01 12:13:14'),
+            (2, '2025-1-1', '2025-1-1 23:59:59'),
+            (3, '2025-1-31', '2025-1-31 23:59:59'),
+            (4, '2025-12-31', '2025-12-31 23:59:59'),
+            (5, NULL, NULL);"""
+    qt_timestamp_two_args_1 """ SELECT 
+                                    TIMESTAMP(dt, '65:43:21') AS 
date_cross_day,
+                                    TIMESTAMP(dttm, '1:23:45') AS 
dttm_cross_day,
+                                    TIMESTAMP(dt, NULL) AS all_null_1,
+                                    TIMESTAMP(dttm, NULL) AS all_null_2
+                                FROM test_timestamp;"""
+    qt_timestamp_two_args_2 """SELECT TIMESTAMP('12:13:14', '11:45:14');"""
+    qt_timestamp_two_args_3 """SELECT TIMESTAMP('2026-01-05 11:45:14+05:30', 
'02:15:30');"""
+
+    explain {
+        sql """SELECT TIMESTAMP(dt, '65:43:21') FROM test_timestamp;"""
+        contains "add_time"
+    }
+    
+    test {
+        sql """SELECT TIMESTAMP('9999-12-31', '65:43:21');"""
+        exception "is invalid";
+    }
+    
+
     // Test constant folding for YEARWEEK function
     testFoldConst("SELECT YEARWEEK('2021-01-01') AS yearweek_mode0")
     testFoldConst("SELECT YEARWEEK('2020-07-01', 1) AS yearweek_mode1")
@@ -2297,6 +2330,20 @@ suite("doc_date_functions_test") {
     testFoldConst("SELECT YEARS_SUB(NULL, 1)")
     testFoldConst("SELECT YEARS_SUB('2020-02-02', NULL)")
 
+    // TIMESTAMP with two args
+    testFoldConst("SELECT TIMESTAMP('2025-11-01', '65:43:21')")
+    testFoldConst("SELECT TIMESTAMP('2025-11-01 12:13:14', '1:23:45')")
+    testFoldConst("SELECT TIMESTAMP('2025-1-1', '23:59:59')")
+    testFoldConst("SELECT TIMESTAMP('2025-1-1 23:59:59', '1:23:45')")
+    testFoldConst("SELECT TIMESTAMP('2025-1-31', '23:59:59')")
+    testFoldConst("SELECT TIMESTAMP('2025-1-31 23:59:59', '1:23:45')")
+    testFoldConst("SELECT TIMESTAMP('2025-12-31', '23:59:59')")
+    testFoldConst("SELECT TIMESTAMP('2025-12-31 23:59:59', '1:23:45')")
+    testFoldConst("SELECT TIMESTAMP(NULL, '1:23:45')")
+    testFoldConst("SELECT TIMESTAMP('2025-11-01', NULL)")
+    testFoldConst("SELECT TIMESTAMP('12:13:14', '11:45:14');")
+    testFoldConst("SELECT TIMESTAMP('2026-01-05 11:45:14+05:30', '02:15:30');")
+
     // // Invalid parameter tests for error conditions
     // testFoldConst("SELECT DAY_CEIL('2023-07-13', -5)")
     // testFoldConst("SELECT HOUR_CEIL('2023-07-13 22:28:18', -5)")


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

Reply via email to