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

panxiaolei 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 4813be5ba31 [improvement](fe) Enhance COALESCE simplification to 
remove all NullLiterals (#62266)
4813be5ba31 is described below

commit 4813be5ba31a18f6875e8451bbe64e849159c79b
Author: Pxl <[email protected]>
AuthorDate: Fri Apr 10 10:57:07 2026 +0800

    [improvement](fe) Enhance COALESCE simplification to remove all 
NullLiterals (#62266)
    
    The existing COALESCE simplification rule in SimplifyConditionalFunction
    only removed leading NullLiteral arguments. When a nullable
    non-NullLiteral argument was encountered, all remaining arguments
    (including trailing/interleaved NullLiterals) were preserved.
    Additionally, an early exit prevented any simplification when the first
    argument was a nullable non-NullLiteral.
    
    For example, `coalesce(null, null, ..., null, i1, null)` was simplified
    to `coalesce(i1, null)` instead of just `i1`.
    
    The improved algorithm:
    1. Skips ALL NullLiteral arguments (not just leading ones)
    2. Truncates at the first non-nullable argument (subsequent args are
    unreachable)
    3. Returns the single remaining expression directly when only one is
    left
    
    ### Release note
    
    Improved COALESCE expression simplification to remove all NULL literal
    arguments and truncate unreachable arguments after the first
    non-nullable expression.
    
    ### Check List (For Author)
    
    - Test: Unit Test
    - Behavior changed: No
    - Does this need documentation: No
    
    Co-authored-by: Copilot <[email protected]>
---
 .../rules/SimplifyConditionalFunction.java         | 26 +++++++++-------------
 .../rules/SimplifyConditionalFunctionTest.java     | 21 +++++++++++++++++
 2 files changed, 32 insertions(+), 15 deletions(-)

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 f4d0e479fd6..7d32fc0963b 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
@@ -50,31 +50,23 @@ public class SimplifyConditionalFunction implements 
ExpressionPatternRuleFactory
     }
 
     /*
-     * coalesce(null,null,expr,...) => coalesce(expr,...)
-     * coalesce(expr1(not null able ), expr2, ...., expr_n) => expr1
-     * coalesce(null,null) => null
-     * coalesce(expr1) => expr1
+     * coalesce(null, ..., null, expr, null) => expr
+     * coalesce(a, null, b, null) => coalesce(a, b)
+     * coalesce(a, b_not_nullable, c) => coalesce(a, b_not_nullable)
+     * coalesce(expr_not_nullable, ...) => expr_not_nullable
+     * coalesce(null, null) => null
+     * coalesce(expr) => expr
      * */
     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 (!(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 < coalesce.arity(); i++) {
             Expression child = coalesce.children().get(i);
             if (child instanceof NullLiteral) {
                 continue;
             }
+            childBuilder.add(child);
             if (!child.nullable()) {
-                return TypeCoercionUtils.ensureSameResultType(coalesce, child, 
ctx.rewriteContext);
-            } else {
-                for (int j = i; j < coalesce.arity(); j++) {
-                    childBuilder.add(coalesce.children().get(j));
-                }
                 break;
             }
         }
@@ -83,6 +75,10 @@ public class SimplifyConditionalFunction implements 
ExpressionPatternRuleFactory
             return TypeCoercionUtils.ensureSameResultType(
                     coalesce, new NullLiteral(coalesce.getDataType()), 
ctx.rewriteContext
             );
+        } else if (newChildren.size() == 1) {
+            return TypeCoercionUtils.ensureSameResultType(
+                    coalesce, newChildren.get(0), ctx.rewriteContext
+            );
         } else {
             return TypeCoercionUtils.ensureSameResultType(
                     coalesce, coalesce.withChildren(newChildren), 
ctx.rewriteContext
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 7808823d36c..24acaf36b9b 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
@@ -72,6 +72,27 @@ public class SimplifyConditionalFunctionTest extends 
ExpressionRewriteTestHelper
         // coalesce(null, nullable_slot, literal) -> coalesce(nullable_slot, 
slot, literal)
         assertRewrite(new Coalesce(slot, nonNullableSlot), new Coalesce(slot, 
nonNullableSlot));
 
+        // coalesce(null, null, ..., null, nullable_slot, null) -> 
nullable_slot
+        // Trailing NullLiterals should also be removed
+        assertRewrite(new Coalesce(NullLiteral.INSTANCE, NullLiteral.INSTANCE, 
NullLiteral.INSTANCE,
+                NullLiteral.INSTANCE, NullLiteral.INSTANCE, slot, 
NullLiteral.INSTANCE), slot);
+
+        // coalesce(nullable_slot, null, null, null) -> nullable_slot
+        // Trailing NullLiterals removed even when first arg is nullable
+        assertRewrite(new Coalesce(slot, NullLiteral.INSTANCE, 
NullLiteral.INSTANCE, NullLiteral.INSTANCE), slot);
+
+        SlotReference slot2 = new SlotReference("c", StringType.INSTANCE, 
true);
+
+        // coalesce(nullable_slot, null, nullable_slot2, null) -> 
coalesce(nullable_slot, nullable_slot2)
+        // Interleaved NullLiterals removed
+        assertRewrite(new Coalesce(slot, NullLiteral.INSTANCE, slot2, 
NullLiteral.INSTANCE),
+                new Coalesce(slot, slot2));
+
+        // coalesce(nullable_slot, null, non_nullable_slot, nullable_slot2) -> 
coalesce(nullable_slot, non_nullable_slot)
+        // Truncate after first non-nullable + remove interleaved NullLiterals
+        assertRewrite(new Coalesce(slot, NullLiteral.INSTANCE, 
nonNullableSlot, slot2),
+                new Coalesce(slot, nonNullableSlot));
+
         SlotReference datetimeSlot = new SlotReference("dt", 
DateTimeV2Type.of(0), false);
         // coalesce(null_datetime(0), non-nullable_slot_datetime(6))
         assertRewrite(


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

Reply via email to