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]