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]