Repository: apache/doris
Pull request #50142: [fix](nereids) fix fold constant return wrong scale of datetime type
Author: login: 924060929
Labels: name: approved
description: Indicates a PR has been approved by one committer.
name: reviewed
name: p0_b
name: dev/2.1.10-merged
name: dev/3.0.6-merged
Created: 2025-04-17T09:53:41Z | Merged: 2025-04-21T07:47:15Z

### What problem does this PR solve?

fix fold constant return wrong scale of datetime type

for example, this sql should return data type `datatime(6)`, but the fold constant rule will direct return the first argument, so return the wrong data type `datetime(0)`
```sql
select nvl(cast('2025-04-17 01:02:03' as datetime(0)), cast('2025-04-17 01:02:03.123456' as datetime(6)))
```


### Check List (For Author)

- Test <!-- At least one of them must be included. -->
    - [ ] Regression test
    - [x] Unit Test
    - [ ] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
        - [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason <!-- Add your reason?  -->

- Behavior changed:
    - [ ] No.
    - [ ] Yes. <!-- Explain the behavior change -->

- Does this need documentation?
    - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg: https://github.com/apache/doris-website/pull/1214 -->

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->




Diff:
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
index 2f2f0b2b6b7b19..058fe9fa7fd3e4 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
@@ -95,6 +95,7 @@
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.coercion.DateLikeType;
 import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.GlobalVariable;
 import org.apache.doris.thrift.TUniqueId;
@@ -539,6 +540,7 @@ public Expression visitBinaryArithmetic(BinaryArithmetic binaryArithmetic, Expre
 
     @Override
     public Expression visitCaseWhen(CaseWhen caseWhen, ExpressionRewriteContext context) {
+        CaseWhen originCaseWhen = caseWhen;
         caseWhen = rewriteChildren(caseWhen, context);
         Expression newDefault = null;
         boolean foundNewDefault = false;
@@ -564,7 +566,10 @@ public Expression visitCaseWhen(CaseWhen caseWhen, ExpressionRewriteContext cont
             defaultResult = newDefault;
         }
         if (whenClauses.isEmpty()) {
-            return defaultResult == null ? new NullLiteral(caseWhen.getDataType()) : defaultResult;
+            return TypeCoercionUtils.ensureSameResultType(
+                    originCaseWhen, defaultResult == null ? new NullLiteral(caseWhen.getDataType()) : defaultResult,
+                    context
+            );
         }
         if (defaultResult == null) {
             if (caseWhen.getDataType().isNullType()) {
@@ -572,21 +577,24 @@ public Expression visitCaseWhen(CaseWhen caseWhen, ExpressionRewriteContext cont
                 // it's safe to return null literal here
                 return new NullLiteral();
             } else {
-                return new CaseWhen(whenClauses);
+                return TypeCoercionUtils.ensureSameResultType(originCaseWhen, new CaseWhen(whenClauses), context);
             }
         }
-        return new CaseWhen(whenClauses, defaultResult);
+        return TypeCoercionUtils.ensureSameResultType(
+                originCaseWhen, new CaseWhen(whenClauses, defaultResult), context
+        );
     }
 
     @Override
     public Expression visitIf(If ifExpr, ExpressionRewriteContext context) {
+        If originIf = ifExpr;
         ifExpr = rewriteChildren(ifExpr, context);
         if (ifExpr.child(0) instanceof NullLiteral || ifExpr.child(0).equals(BooleanLiteral.FALSE)) {
-            return ifExpr.child(2);
+            return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.child(2), context);
         } else if (ifExpr.child(0).equals(BooleanLiteral.TRUE)) {
-            return ifExpr.child(1);
+            return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.child(1), context);
         }
-        return ifExpr;
+        return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr, context);
     }
 
     @Override
@@ -684,17 +692,20 @@ public Expression visitVersion(Version version, ExpressionRewriteContext context
 
     @Override
     public Expression visitNvl(Nvl nvl, ExpressionRewriteContext context) {
+        Nvl originNvl = nvl;
+        nvl = rewriteChildren(nvl, context);
+
         for (Expression expr : nvl.children()) {
             if (expr.isLiteral()) {
                 if (!expr.isNullLiteral()) {
-                    return expr;
+                    return TypeCoercionUtils.ensureSameResultType(originNvl, expr, context);
                 }
             } else {
-                return nvl;
+                return TypeCoercionUtils.ensureSameResultType(originNvl, nvl, context);
             }
         }
         // all nulls
-        return nvl.child(0);
+        return TypeCoercionUtils.ensureSameResultType(originNvl, nvl.child(0), context);
     }
 
     private <E extends Expression> E rewriteChildren(E expr, ExpressionRewriteContext context) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunction.java
index 6862e138ac981f..f4d0e479fd6468 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunction.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.nereids.rules.expression.rules;
 
+import org.apache.doris.nereids.rules.expression.ExpressionMatchingContext;
 import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher;
 import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory;
 import org.apache.doris.nereids.rules.expression.ExpressionRuleType;
@@ -26,6 +27,7 @@
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Nullable;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Nvl;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.util.TypeCoercionUtils;
 
 import com.google.common.collect.ImmutableList;
 
@@ -38,11 +40,11 @@ public class SimplifyConditionalFunction implements ExpressionPatternRuleFactory
     @Override
     public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
         return ImmutableList.of(
-                matchesType(Coalesce.class).then(SimplifyConditionalFunction::rewriteCoalesce)
+                matchesType(Coalesce.class).thenApply(SimplifyConditionalFunction::rewriteCoalesce)
                         .toRule(ExpressionRuleType.SIMPLIFY_CONDITIONAL_FUNCTION),
-                matchesType(Nvl.class).then(SimplifyConditionalFunction::rewriteNvl)
+                matchesType(Nvl.class).thenApply(SimplifyConditionalFunction::rewriteNvl)
                         .toRule(ExpressionRuleType.SIMPLIFY_CONDITIONAL_FUNCTION),
-                matchesType(NullIf.class).then(SimplifyConditionalFunction::rewriteNullIf)
+                matchesType(NullIf.class).thenApply(SimplifyConditionalFunction::rewriteNullIf)
                         .toRule(ExpressionRuleType.SIMPLIFY_CONDITIONAL_FUNCTION)
         );
     }
@@ -53,33 +55,38 @@ public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
      * coalesce(null,null) => null
      * coalesce(expr1) => expr1
      * */
-    private static Expression rewriteCoalesce(Coalesce expression) {
-        if (1 == expression.arity()) {
-            return expression.child(0);
+    private static Expression rewriteCoalesce(ExpressionMatchingContext<Coalesce> ctx) {
+        Coalesce coalesce = ctx.expr;
+        if (1 == coalesce.arity()) {
+            return TypeCoercionUtils.ensureSameResultType(coalesce, coalesce.child(0), ctx.rewriteContext);
         }
-        if (!(expression.child(0) instanceof NullLiteral) && expression.child(0).nullable()) {
-            return expression;
+        if (!(coalesce.child(0) instanceof NullLiteral) && coalesce.child(0).nullable()) {
+            return TypeCoercionUtils.ensureSameResultType(coalesce, coalesce, ctx.rewriteContext);
         }
         ImmutableList.Builder<Expression> childBuilder = ImmutableList.builder();
-        for (int i = 0; i < expression.arity(); i++) {
-            Expression child = expression.children().get(i);
+        for (int i = 0; i < coalesce.arity(); i++) {
+            Expression child = coalesce.children().get(i);
             if (child instanceof NullLiteral) {
                 continue;
             }
             if (!child.nullable()) {
-                return child;
+                return TypeCoercionUtils.ensureSameResultType(coalesce, child, ctx.rewriteContext);
             } else {
-                for (int j = i; j < expression.arity(); j++) {
-                    childBuilder.add(expression.children().get(j));
+                for (int j = i; j < coalesce.arity(); j++) {
+                    childBuilder.add(coalesce.children().get(j));
                 }
                 break;
             }
         }
         List<Expression> newChildren = childBuilder.build();
         if (newChildren.isEmpty()) {
-            return new NullLiteral(expression.getDataType());
+            return TypeCoercionUtils.ensureSameResultType(
+                    coalesce, new NullLiteral(coalesce.getDataType()), ctx.rewriteContext
+            );
         } else {
-            return expression.withChildren(newChildren);
+            return TypeCoercionUtils.ensureSameResultType(
+                    coalesce, coalesce.withChildren(newChildren), ctx.rewriteContext
+            );
         }
     }
 
@@ -87,12 +94,13 @@ private static Expression rewriteCoalesce(Coalesce expression) {
     * nvl(null,R) => R
     * nvl(L(not-nullable ),R) => L
     * */
-    private static Expression rewriteNvl(Nvl nvl) {
+    private static Expression rewriteNvl(ExpressionMatchingContext<Nvl> ctx) {
+        Nvl nvl = ctx.expr;
         if (nvl.child(0) instanceof NullLiteral) {
-            return nvl.child(1);
+            return TypeCoercionUtils.ensureSameResultType(nvl, nvl.child(1), ctx.rewriteContext);
         }
         if (!nvl.child(0).nullable()) {
-            return nvl.child(0);
+            return TypeCoercionUtils.ensureSameResultType(nvl, nvl.child(0), ctx.rewriteContext);
         }
         return nvl;
     }
@@ -101,9 +109,12 @@ private static Expression rewriteNvl(Nvl nvl) {
     * nullif(null, R) => Null
     * nullif(L, null) => Null
      */
-    private static Expression rewriteNullIf(NullIf nullIf) {
+    private static Expression rewriteNullIf(ExpressionMatchingContext<NullIf> ctx) {
+        NullIf nullIf = ctx.expr;
         if (nullIf.child(0) instanceof NullLiteral || nullIf.child(1) instanceof NullLiteral) {
-            return new Nullable(nullIf.child(0));
+            return TypeCoercionUtils.ensureSameResultType(
+                    nullIf, new Nullable(nullIf.child(0)), ctx.rewriteContext
+            );
         } else {
             return nullIf;
         }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
index cde5cb767905e9..769bda55ad5905 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
@@ -24,6 +24,8 @@
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.annotation.Developing;
 import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
+import org.apache.doris.nereids.rules.expression.rules.FoldConstantRuleOnFE;
 import org.apache.doris.nereids.trees.expressions.Add;
 import org.apache.doris.nereids.trees.expressions.BinaryArithmetic;
 import org.apache.doris.nereids.trees.expressions.BinaryOperator;
@@ -153,6 +155,26 @@ public class TypeCoercionUtils {
 
     private static final Logger LOG = LogManager.getLogger(TypeCoercionUtils.class);
 
+    /**
+     * ensure the result's data type equals to the originExpr's dataType,
+     * ATTN: this method usually used in fold constant rule
+     */
+    public static Expression ensureSameResultType(
+            Expression originExpr, Expression result, ExpressionRewriteContext context) {
+        DataType originDataType = originExpr.getDataType();
+        DataType newDataType = result.getDataType();
+        if (originDataType.equals(newDataType)) {
+            return result;
+        }
+        // backend can direct use all string like type without cast
+        if (originDataType.isStringLikeType() && newDataType.isStringLikeType()) {
+            return result;
+        }
+        return FoldConstantRuleOnFE.PATTERN_MATCH_INSTANCE.visitCast(
+                new Cast(result, originDataType), context
+        );
+    }
+
     /**
      * Return Optional.empty() if we cannot do implicit cast.
      */
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 a5c7341a5e6ba2..f2593418a4374c 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
@@ -25,6 +25,8 @@
 import org.apache.doris.nereids.rules.analysis.ExpressionAnalyzer;
 import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule;
 import org.apache.doris.nereids.rules.expression.rules.FoldConstantRuleOnFE;
+import org.apache.doris.nereids.rules.expression.rules.SimplifyConditionalFunction;
+import org.apache.doris.nereids.trees.expressions.CaseWhen;
 import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.GreaterThan;
@@ -122,6 +124,15 @@ void testCaseWhenFold() {
         assertRewriteAfterTypeCoercion("case when null = 2 then 1 else 4 end", "4");
         assertRewriteAfterTypeCoercion("case when null = 2 then 1 end", "null");
         assertRewriteAfterTypeCoercion("case when TA = TB then 1 when TC is null then 2 end", "CASE WHEN (TA = TB) THEN 1 WHEN TC IS NULL THEN 2 END");
+
+        // make sure the case when return datetime(6)
+        Expression analyzedCaseWhen = ExpressionAnalyzer.analyzeFunction(null, null, PARSER.parseExpression(
+                "case when true then cast('2025-04-17' as datetime(0)) else cast('2025-04-18 01:02:03.123456' as datetime(6)) end"));
+        Assertions.assertEquals(DateTimeV2Type.of(6), analyzedCaseWhen.getDataType());
+        Assertions.assertEquals(DateTimeV2Type.of(6), ((CaseWhen) analyzedCaseWhen).getWhenClauses().get(0).getResult().getDataType());
+        Assertions.assertEquals(DateTimeV2Type.of(6), ((CaseWhen) analyzedCaseWhen).getDefaultValue().get().getDataType());
+        Expression foldCaseWhen = executor.rewrite(analyzedCaseWhen, context);
+        Assertions.assertEquals(new DateTimeV2Literal(DateTimeV2Type.of(6), "2025-04-17"), foldCaseWhen);
     }
 
     @Test
@@ -1175,7 +1186,8 @@ void testFoldNvl() {
         executor = new ExpressionRuleExecutor(ImmutableList.of(
                 ExpressionAnalyzer.FUNCTION_ANALYZER_RULE,
                 bottomUp(
-                        FoldConstantRule.INSTANCE
+                        FoldConstantRule.INSTANCE,
+                        SimplifyConditionalFunction.INSTANCE
                 )
         ));
 
@@ -1183,6 +1195,12 @@ void testFoldNvl() {
         assertRewriteExpression("nvl(NULL, NULL)", "NULL");
         assertRewriteAfterTypeCoercion("nvl(IA, NULL)", "ifnull(IA, NULL)");
         assertRewriteAfterTypeCoercion("nvl(IA, 1)", "ifnull(IA, 1)");
+
+        Expression foldNvl = executor.rewrite(
+                PARSER.parseExpression("nvl(cast('2025-04-17' as datetime(0)), cast('2025-04-18 01:02:03.123456' as datetime(6)))"),
+                context
+        );
+        Assertions.assertEquals(new DateTimeV2Literal(DateTimeV2Type.of(6), "2025-04-17"), foldNvl);
     }
 
     private void assertRewriteExpression(String actualExpression, String expectedExpression) {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunctionTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunctionTest.java
index 7ba9cf09ff26fd..152c0f542e3140 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunctionTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyConditionalFunctionTest.java
@@ -19,6 +19,7 @@
 
 import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper;
 import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
+import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.NullIf;
@@ -26,6 +27,7 @@
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Nvl;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.StringType;
 import org.apache.doris.nereids.types.VarcharType;
 
@@ -71,6 +73,18 @@ public void testCoalesce() {
 
         // coalesce(null, nullable_slot, literal) -> coalesce(nullable_slot, slot, literal)
         assertRewrite(new Coalesce(slot, nonNullableSlot), new Coalesce(slot, nonNullableSlot));
+
+        SlotReference datetimeSlot = new SlotReference("dt", DateTimeV2Type.of(0), false);
+        // coalesce(null_datetime(0), non-nullable_slot_datetime(6))
+        assertRewrite(
+                new Coalesce(new NullLiteral(DateTimeV2Type.of(6)), datetimeSlot),
+                new Cast(datetimeSlot, DateTimeV2Type.of(6))
+        );
+        // coalesce(non-nullable_slot_datetime(6), null_datetime(0))
+        assertRewrite(
+                new Coalesce(datetimeSlot, new NullLiteral(DateTimeV2Type.of(6))),
+                new Cast(datetimeSlot, DateTimeV2Type.of(6))
+        );
     }
 
     @Test
@@ -92,6 +106,18 @@ public void testNvl() {
 
         // nvl(null, null) -> null
         assertRewrite(new Nvl(NullLiteral.INSTANCE, NullLiteral.INSTANCE), new NullLiteral(BooleanType.INSTANCE));
+
+        SlotReference datetimeSlot = new SlotReference("dt", DateTimeV2Type.of(0), false);
+        // nvl(null_datetime(0), non-nullable_slot_datetime(6))
+        assertRewrite(
+                new Nvl(new NullLiteral(DateTimeV2Type.of(6)), datetimeSlot),
+                new Cast(datetimeSlot, DateTimeV2Type.of(6))
+        );
+        // nvl(non-nullable_slot_datetime(6), null_datetime(0))
+        assertRewrite(
+                new Nvl(datetimeSlot, new NullLiteral(DateTimeV2Type.of(6))),
+                new Cast(datetimeSlot, DateTimeV2Type.of(6))
+        );
     }
 
     @Test
@@ -108,6 +134,15 @@ public void testNullIf() {
 
         // nullif(non-nullable_slot, null) -> non-nullable_slot
         assertRewrite(new NullIf(nonNullableSlot, NullLiteral.INSTANCE), new Nullable(nonNullableSlot));
+
+        // nullif(null_datetime(0), null_datetime(6)) -> null_datetime(6)
+        assertRewrite(
+                new NullIf(
+                        new NullLiteral(DateTimeV2Type.of(0)),
+                        new NullLiteral(DateTimeV2Type.of(6))
+                ),
+                new Cast(new Nullable(new NullLiteral(DateTimeV2Type.of(0))), DateTimeV2Type.of(6))
+        );
     }
 
 }


Reviews:
user: login: starocean999
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T13:50:14Z
user: login: 924060929
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T14:01:34Z
user: login: morrySnow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:14:15Z
user: login: 924060929
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T15:23:06Z
user: login: starocean999
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T06:15:46Z
user: login: morrySnow
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T07:44:48Z

Review comments:
diff_hunk: @@ -153,6 +155,25 @@ public class TypeCoercionUtils {
 
     private static final Logger LOG = LogManager.getLogger(TypeCoercionUtils.class);
 
+    /**
+     * ensure the result's data type equals to the originExpr's dataType
+     */
+    public static Expression ensureSameResultType(
+            Expression originExpr, Expression result, ExpressionRewriteContext context) {
+        DataType originDataType = originExpr.getDataType();
+        DataType newDataType = result.getDataType();
+        if (originDataType.equals(newDataType)) {
+            return result;
+        }
+        // backend can direct use all string like type without cast
+        if (originDataType.isStringLikeType() && newDataType.isStringLikeType()) {
+            return result;
+        }
+        return FoldConstantRuleOnFE.PATTERN_MATCH_INSTANCE.visitCast(
path: fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
user: login: starocean999
body: why use FoldConstantRuleOnFE here?
created_at: 2025-04-17T13:50:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -153,6 +155,25 @@ public class TypeCoercionUtils {
 
     private static final Logger LOG = LogManager.getLogger(TypeCoercionUtils.class);
 
+    /**
+     * ensure the result's data type equals to the originExpr's dataType
+     */
+    public static Expression ensureSameResultType(
+            Expression originExpr, Expression result, ExpressionRewriteContext context) {
+        DataType originDataType = originExpr.getDataType();
+        DataType newDataType = result.getDataType();
+        if (originDataType.equals(newDataType)) {
+            return result;
+        }
+        // backend can direct use all string like type without cast
+        if (originDataType.isStringLikeType() && newDataType.isStringLikeType()) {
+            return result;
+        }
+        return FoldConstantRuleOnFE.PATTERN_MATCH_INSTANCE.visitCast(
path: fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
user: login: 924060929
body: for fast fold this cast
created_at: 2025-04-17T14:01:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -153,6 +155,25 @@ public class TypeCoercionUtils {
 
     private static final Logger LOG = LogManager.getLogger(TypeCoercionUtils.class);
 
+    /**
+     * ensure the result's data type equals to the originExpr's dataType
+     */
+    public static Expression ensureSameResultType(
+            Expression originExpr, Expression result, ExpressionRewriteContext context) {
+        DataType originDataType = originExpr.getDataType();
+        DataType newDataType = result.getDataType();
+        if (originDataType.equals(newDataType)) {
+            return result;
+        }
+        // backend can direct use all string like type without cast
+        if (originDataType.isStringLikeType() && newDataType.isStringLikeType()) {
+            return result;
+        }
+        return FoldConstantRuleOnFE.PATTERN_MATCH_INSTANCE.visitCast(
path: fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
user: login: morrySnow
body: functio name should related to constant folding
created_at: 2025-04-17T15:13:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -153,6 +155,25 @@ public class TypeCoercionUtils {
 
     private static final Logger LOG = LogManager.getLogger(TypeCoercionUtils.class);
 
+    /**
+     * ensure the result's data type equals to the originExpr's dataType
+     */
+    public static Expression ensureSameResultType(
+            Expression originExpr, Expression result, ExpressionRewriteContext context) {
+        DataType originDataType = originExpr.getDataType();
+        DataType newDataType = result.getDataType();
+        if (originDataType.equals(newDataType)) {
+            return result;
+        }
+        // backend can direct use all string like type without cast
+        if (originDataType.isStringLikeType() && newDataType.isStringLikeType()) {
+            return result;
+        }
+        return FoldConstantRuleOnFE.PATTERN_MATCH_INSTANCE.visitCast(
path: fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
user: login: 924060929
body: > functio name should related to constant folding

`ensureSameResultTypeAndTryFoldCast` is too long
created_at: 2025-04-17T15:23:06Z
author_association: CONTRIBUTOR

PR comments:
user: login: hello-stephen
created_at: 2025-04-17T09:53:48Z
body: 
Thank you for your contribution to Apache Doris.
Don't know what should be done next? See [How to process your PR](https://cwiki.apache.org/confluence/display/DORIS/How+to+process+your+PR).

Please clearly describe your PR:
1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
3. What features were added. Why was this function added?
4. Which code was refactored and why was this part of the code refactored?
5. Which functions were optimized and what is the difference before and after the optimization?
    
author_association: CONTRIBUTOR
user: login: 924060929
created_at: 2025-04-17T09:53:56Z
body: run buildall
author_association: CONTRIBUTOR
user: login: 924060929
created_at: 2025-04-17T10:17:20Z
body: run buildall
author_association: CONTRIBUTOR
user: login: 924060929
created_at: 2025-04-17T10:20:49Z
body: run buildall
author_association: CONTRIBUTOR
user: login: 924060929
created_at: 2025-04-17T10:25:49Z
body: run buildall
author_association: CONTRIBUTOR
user: login: doris-robot
created_at: 2025-04-17T10:44:49Z
body: 
<details>
<summary>TPC-H: <b>Total hot run time: 33979 ms</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit e5624acea876a32787cd79a52b1a775949d09b64, data reload: false

------ Round 1 ----------------------------------
q1	26022	5072	5106	5072
q2	2062	278	178	178
q3	10389	1215	720	720
q4	10224	984	524	524
q5	7543	2392	2302	2302
q6	185	160	131	131
q7	903	778	636	636
q8	9302	1271	998	998
q9	6955	5084	5120	5084
q10	6849	2306	1890	1890
q11	477	286	281	281
q12	345	354	222	222
q13	17781	3680	3170	3170
q14	218	231	205	205
q15	548	493	481	481
q16	453	444	403	403
q17	585	849	372	372
q18	7487	7372	7078	7078
q19	2027	937	555	555
q20	334	326	220	220
q21	4113	3369	2472	2472
q22	1052	985	999	985
Total cold run time: 115854 ms
Total hot run time: 33979 ms

----- Round 2, with runtime_filter_mode=off -----
q1	5215	5044	5080	5044
q2	234	333	234	234
q3	2189	2688	2257	2257
q4	1401	1807	1432	1432
q5	4415	4405	4337	4337
q6	214	168	126	126
q7	1971	1903	1772	1772
q8	2614	2547	2548	2547
q9	7212	7323	7185	7185
q10	2976	3198	2747	2747
q11	577	512	495	495
q12	683	761	595	595
q13	3522	3853	3297	3297
q14	314	298	272	272
q15	528	488	480	480
q16	466	509	465	465
q17	1154	1524	1446	1446
q18	7769	7671	7481	7481
q19	808	803	991	803
q20	1925	1982	1833	1833
q21	5201	4830	4770	4770
q22	1129	1043	1017	1017
Total cold run time: 52517 ms
Total hot run time: 50635 ms
```
</details>

author_association: NONE
user: login: doris-robot
created_at: 2025-04-17T10:57:02Z
body: 
<details>
<summary>TPC-DS: <b>Total hot run time: 193012 ms</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit e5624acea876a32787cd79a52b1a775949d09b64, data reload: false

query1	1395	1089	1040	1040
query2	6354	1776	1779	1776
query3	11183	4606	4463	4463
query4	53633	25389	23513	23513
query5	4947	507	470	470
query6	347	206	196	196
query7	4877	489	273	273
query8	315	244	223	223
query9	5193	2562	2555	2555
query10	427	311	254	254
query11	15136	15028	14834	14834
query12	153	113	105	105
query13	1025	514	407	407
query14	10102	6421	6337	6337
query15	216	197	187	187
query16	7082	698	507	507
query17	1074	730	560	560
query18	1555	409	298	298
query19	203	186	173	173
query20	132	121	128	121
query21	207	123	106	106
query22	4568	4671	4416	4416
query23	34164	33567	33557	33557
query24	6707	2406	2454	2406
query25	494	467	399	399
query26	676	270	149	149
query27	2289	512	333	333
query28	2987	2147	2132	2132
query29	556	555	439	439
query30	272	224	186	186
query31	863	843	796	796
query32	73	60	64	60
query33	452	351	308	308
query34	779	869	519	519
query35	810	850	777	777
query36	938	1013	887	887
query37	130	103	85	85
query38	4172	4260	4256	4256
query39	1532	1457	1465	1457
query40	228	123	118	118
query41	59	57	59	57
query42	127	114	114	114
query43	510	495	468	468
query44	1339	824	811	811
query45	185	192	169	169
query46	851	1041	676	676
query47	1876	1922	1835	1835
query48	382	418	339	339
query49	678	546	412	412
query50	648	715	410	410
query51	4194	4244	4200	4200
query52	113	110	96	96
query53	235	255	182	182
query54	566	564	522	522
query55	83	85	83	83
query56	299	291	281	281
query57	1178	1193	1164	1164
query58	260	264	265	264
query59	2767	2803	2725	2725
query60	331	335	302	302
query61	133	165	132	132
query62	739	747	673	673
query63	225	191	185	185
query64	1749	1054	677	677
query65	4476	4261	4232	4232
query66	782	397	301	301
query67	16060	15653	15466	15466
query68	7566	872	504	504
query69	537	297	257	257
query70	1157	1061	1052	1052
query71	489	317	279	279
query72	5962	4784	5030	4784
query73	1504	683	345	345
query74	9032	9071	8951	8951
query75	3833	3216	2684	2684
query76	4205	1173	738	738
query77	611	374	276	276
query78	10149	10233	9270	9270
query79	2341	812	557	557
query80	636	498	437	437
query81	492	264	216	216
query82	372	128	96	96
query83	281	244	218	218
query84	293	99	89	89
query85	786	353	306	306
query86	379	314	289	289
query87	4444	4372	4263	4263
query88	3523	2238	2213	2213
query89	399	314	280	280
query90	1771	206	212	206
query91	144	149	108	108
query92	79	59	56	56
query93	1867	946	580	580
query94	645	410	309	309
query95	372	290	287	287
query96	494	559	276	276
query97	3096	3209	3146	3146
query98	233	207	203	203
query99	1344	1370	1283	1283
Total cold run time: 298127 ms
Total hot run time: 193012 ms
```
</details>

author_association: NONE
user: login: doris-robot
created_at: 2025-04-17T11:02:16Z
body: 
<details>
<summary>ClickBench: <b>Total hot run time: 29.61 s</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit e5624acea876a32787cd79a52b1a775949d09b64, data reload: false

query1	0.04	0.04	0.02
query2	0.12	0.10	0.11
query3	0.25	0.20	0.19
query4	1.60	0.19	0.19
query5	0.62	0.57	0.58
query6	1.18	0.72	0.72
query7	0.02	0.02	0.02
query8	0.04	0.04	0.03
query9	0.58	0.53	0.51
query10	0.57	0.57	0.58
query11	0.15	0.11	0.11
query12	0.14	0.12	0.11
query13	0.61	0.60	0.60
query14	1.20	1.17	1.20
query15	0.88	0.85	0.86
query16	0.40	0.38	0.37
query17	1.03	1.04	1.04
query18	0.22	0.20	0.20
query19	1.93	1.80	1.77
query20	0.01	0.01	0.01
query21	15.40	0.93	0.56
query22	0.74	1.26	0.76
query23	14.75	1.39	0.66
query24	6.78	2.33	0.62
query25	0.54	0.18	0.06
query26	0.65	0.16	0.13
query27	0.06	0.05	0.05
query28	9.95	0.87	0.43
query29	12.56	4.06	3.34
query30	0.24	0.09	0.06
query31	2.84	0.58	0.39
query32	3.22	0.54	0.47
query33	3.06	3.04	3.07
query34	15.61	5.11	4.52
query35	4.56	4.54	4.55
query36	0.66	0.50	0.49
query37	0.08	0.06	0.07
query38	0.05	0.04	0.04
query39	0.03	0.02	0.03
query40	0.17	0.14	0.14
query41	0.08	0.03	0.03
query42	0.03	0.02	0.02
query43	0.04	0.03	0.03
Total cold run time: 103.69 s
Total hot run time: 29.61 s
```
</details>

author_association: NONE
user: login: 924060929
created_at: 2025-04-18T02:35:56Z
body: run buildall
author_association: CONTRIBUTOR
user: login: doris-robot
created_at: 2025-04-18T04:20:42Z
body: 
<details>
<summary>TPC-H: <b>Total hot run time: 34047 ms</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 20724c0016e331ddf88a40cfd6d5e8d476c1eba4, data reload: false

------ Round 1 ----------------------------------
q1	26217	5095	5057	5057
q2	2073	293	186	186
q3	10378	1269	708	708
q4	10216	1009	529	529
q5	7517	2390	2374	2374
q6	182	163	131	131
q7	915	745	637	637
q8	9304	1285	1088	1088
q9	6723	5135	5154	5135
q10	6839	2321	1897	1897
q11	478	284	264	264
q12	351	352	225	225
q13	17805	3673	3064	3064
q14	234	230	205	205
q15	533	491	494	491
q16	444	446	402	402
q17	595	878	372	372
q18	7584	7132	7220	7132
q19	1714	967	527	527
q20	326	330	216	216
q21	3953	2623	2435	2435
q22	1078	1041	972	972
Total cold run time: 115459 ms
Total hot run time: 34047 ms

----- Round 2, with runtime_filter_mode=off -----
q1	5189	5091	5091	5091
q2	242	343	226	226
q3	2141	2635	2275	2275
q4	1405	1816	1365	1365
q5	4496	4459	4400	4400
q6	219	168	128	128
q7	2056	1896	1778	1778
q8	2593	2484	2491	2484
q9	7340	7227	6935	6935
q10	3004	3229	2744	2744
q11	587	508	484	484
q12	691	767	622	622
q13	3547	3867	3269	3269
q14	292	286	286	286
q15	537	493	516	493
q16	481	526	457	457
q17	1152	1568	1414	1414
q18	7877	7589	7491	7491
q19	807	801	917	801
q20	1972	2052	1855	1855
q21	5255	4922	4912	4912
q22	1095	1066	1051	1051
Total cold run time: 52978 ms
Total hot run time: 50561 ms
```
</details>

author_association: NONE
user: login: doris-robot
created_at: 2025-04-18T04:33:03Z
body: 
<details>
<summary>TPC-DS: <b>Total hot run time: 192994 ms</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 20724c0016e331ddf88a40cfd6d5e8d476c1eba4, data reload: false

query1	1391	1104	1108	1104
query2	6249	1828	1777	1777
query3	11041	4474	4733	4474
query4	54709	25216	23530	23530
query5	4960	506	468	468
query6	321	197	196	196
query7	4902	515	287	287
query8	298	272	243	243
query9	5464	2556	2541	2541
query10	404	345	265	265
query11	14981	15188	14714	14714
query12	155	112	105	105
query13	1032	504	389	389
query14	10152	6256	6250	6250
query15	198	199	181	181
query16	7182	624	490	490
query17	1075	724	572	572
query18	1692	411	299	299
query19	187	187	161	161
query20	130	129	130	129
query21	210	128	106	106
query22	4397	4543	4259	4259
query23	34241	33594	33470	33470
query24	6512	2446	2451	2446
query25	477	497	420	420
query26	701	272	157	157
query27	2254	495	335	335
query28	3233	2142	2119	2119
query29	616	605	464	464
query30	274	224	193	193
query31	864	862	789	789
query32	78	66	66	66
query33	466	380	373	373
query34	761	868	535	535
query35	825	851	765	765
query36	962	1009	934	934
query37	118	108	76	76
query38	4251	4323	4184	4184
query39	1481	1467	1448	1448
query40	218	123	104	104
query41	53	64	64	64
query42	129	119	105	105
query43	515	515	465	465
query44	1315	844	821	821
query45	182	177	168	168
query46	894	1032	665	665
query47	1847	1877	1772	1772
query48	398	426	302	302
query49	683	503	454	454
query50	672	748	424	424
query51	4230	4260	4259	4259
query52	108	110	99	99
query53	237	261	189	189
query54	587	598	531	531
query55	88	90	81	81
query56	323	308	292	292
query57	1190	1190	1144	1144
query58	281	274	261	261
query59	2628	2740	2616	2616
query60	336	333	318	318
query61	129	135	157	135
query62	769	759	665	665
query63	227	201	193	193
query64	1920	1143	820	820
query65	4425	4253	4273	4253
query66	749	397	301	301
query67	15787	15514	15194	15194
query68	8273	895	516	516
query69	577	307	259	259
query70	1190	1084	1134	1084
query71	498	322	299	299
query72	5532	4866	5068	4866
query73	1491	706	347	347
query74	8938	9124	9027	9027
query75	3943	3202	2642	2642
query76	4259	1197	742	742
query77	613	366	289	289
query78	9959	10024	9297	9297
query79	6383	806	545	545
query80	686	502	433	433
query81	487	261	218	218
query82	733	125	96	96
query83	347	251	247	247
query84	295	105	83	83
query85	807	355	382	355
query86	357	315	303	303
query87	4501	4415	4375	4375
query88	3427	2242	2233	2233
query89	453	313	290	290
query90	1949	209	216	209
query91	132	142	109	109
query92	73	59	55	55
query93	3257	933	577	577
query94	689	417	315	315
query95	369	287	291	287
query96	472	566	270	270
query97	3197	3238	3137	3137
query98	218	205	198	198
query99	1423	1418	1282	1282
Total cold run time: 305692 ms
Total hot run time: 192994 ms
```
</details>

author_association: NONE
user: login: doris-robot
created_at: 2025-04-18T04:38:15Z
body: 
<details>
<summary>ClickBench: <b>Total hot run time: 29.57 s</b></summary>

```
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 20724c0016e331ddf88a40cfd6d5e8d476c1eba4, data reload: false

query1	0.04	0.03	0.03
query2	0.13	0.11	0.11
query3	0.26	0.19	0.20
query4	1.60	0.19	0.20
query5	0.58	0.59	0.59
query6	1.19	0.71	0.70
query7	0.03	0.02	0.02
query8	0.04	0.03	0.04
query9	0.58	0.52	0.51
query10	0.58	0.56	0.56
query11	0.16	0.11	0.11
query12	0.16	0.11	0.11
query13	0.61	0.60	0.60
query14	1.16	1.20	1.17
query15	0.89	0.86	0.86
query16	0.39	0.38	0.38
query17	1.01	1.04	1.02
query18	0.22	0.19	0.19
query19	1.90	1.77	1.84
query20	0.02	0.01	0.02
query21	15.41	0.92	0.56
query22	0.75	1.19	0.67
query23	14.94	1.40	0.63
query24	7.55	1.35	0.80
query25	0.50	0.15	0.11
query26	0.60	0.17	0.15
query27	0.05	0.05	0.04
query28	9.72	0.83	0.42
query29	12.54	3.96	3.34
query30	0.25	0.09	0.06
query31	2.82	0.58	0.38
query32	3.23	0.54	0.46
query33	3.07	3.07	3.05
query34	15.84	5.07	4.47
query35	4.51	4.55	4.47
query36	0.67	0.50	0.47
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.02	0.03
query40	0.16	0.15	0.13
query41	0.09	0.04	0.03
query42	0.04	0.03	0.02
query43	0.04	0.04	0.04
Total cold run time: 104.51 s
Total hot run time: 29.57 s
```
</details>

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-21T06:16:50Z
body: PR approved by at least one committer and no changes requested.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-21T06:16:52Z
body: PR approved by anyone and no changes requested.
author_association: CONTRIBUTOR