You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2026/02/12 15:39:45 UTC
(doris) branch branch-4.0 updated: branch-4.0: [fix](nereids) fix empty layer in CommonSubExpressionOpt when WhenClause is the only common sub-expression #60435 (#60619)
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 d2a73a13866 branch-4.0: [fix](nereids) fix empty layer in CommonSubExpressionOpt when WhenClause is the only common sub-expression #60435 (#60619)
d2a73a13866 is described below
commit d2a73a138666626f4c8dafb13aeb7b284a7c1135
Author: github-actions[bot] <41...@users.noreply.github.com>
AuthorDate: Thu Feb 12 23:39:37 2026 +0800
branch-4.0: [fix](nereids) fix empty layer in CommonSubExpressionOpt when WhenClause is the only common sub-expression #60435 (#60619)
Cherry-picked from #60435
Co-authored-by: minghong <zh...@selectdb.com>
---
.../post/CommonSubExpressionCollector.java | 2 +
.../processor/post/CommonSubExpressionOpt.java | 16 ++-----
.../postprocess/CommonSubExpressionTest.java | 50 ++++++++++++++++++++++
3 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionCollector.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionCollector.java
index 11d8ca00744..cccf9dbba07 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionCollector.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionCollector.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.trees.expressions.ArrayItemReference;
import org.apache.doris.nereids.trees.expressions.ArrayItemReference.ArrayItemSlot;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.SessionVarGuardExpr;
+import org.apache.doris.nereids.trees.expressions.WhenClause;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Lambda;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -74,6 +75,7 @@ public class CommonSubExpressionCollector extends ExpressionVisitor<Integer, Boo
// TODO: could not extract common expression when expression contains same lambda expression
// because ArrayItemSlot in Lambda are not same.
if (expressions.contains(expr)
+ && !(expr instanceof WhenClause)
&& !(inLambda && expr.containsType(ArrayItemSlot.class, ArrayItemReference.class))) {
Set<Expression> commonExpression = getExpressionsFromDepthMap(depth, commonExprByDepth);
commonExpression.add(expr);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionOpt.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionOpt.java
index 86dabb057da..0d9e3abc25a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionOpt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/CommonSubExpressionOpt.java
@@ -22,7 +22,6 @@ import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.expressions.WhenClause;
import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
@@ -78,17 +77,10 @@ public class CommonSubExpressionOpt extends PlanPostProcessor {
Set<Expression> exprsInDepth = CommonSubExpressionCollector
.getExpressionsFromDepthMap(i, collector.commonExprByDepth);
exprsInDepth.forEach(expr -> {
- if (!(expr instanceof WhenClause)) {
- // case whenClause1 whenClause2 END
- // whenClause should not be regarded as common-sub-expression, because
- // cse will be replaced by a slot, after rewrite the case clause becomes:
- // 'case slot whenClause2 END'
- // This is illegal.
- Expression rewritten = expr.accept(ExpressionReplacer.INSTANCE, aliasMap);
- // if rewritten is already alias, use it directly, because in materialized view rewriting
- // Should keep out slot immutably after rewritten successfully
- aliasMap.put(expr, rewritten instanceof Alias ? (Alias) rewritten : new Alias(rewritten));
- }
+ Expression rewritten = expr.accept(ExpressionReplacer.INSTANCE, aliasMap);
+ // if rewritten is already alias, use it directly, because in materialized view rewriting
+ // Should keep out slot immutably after rewritten successfully
+ aliasMap.put(expr, rewritten instanceof Alias ? (Alias) rewritten : new Alias(rewritten));
});
for (Alias alias : aliasMap.values()) {
if (previousAlias.contains(alias)) {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/CommonSubExpressionTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/CommonSubExpressionTest.java
index c9a20f65e69..1d5ac1dc24a 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/CommonSubExpressionTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/CommonSubExpressionTest.java
@@ -44,6 +44,7 @@ import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -150,4 +151,53 @@ public class CommonSubExpressionTest extends ExpressionRewriteTestHelper {
}
}
+ @Test
+ public void testCaseWhenSubExprExtracted() {
+ // a+b appears 4 times inside CASE WHEN, should be collected as common sub-expression
+ // WhenClause itself should NOT be collected
+ List<NamedExpression> exprs = parseProjections(
+ "CASE WHEN (a+b > 10) THEN (a+b) WHEN (a+b > 5) THEN (a+b) ELSE 0 END");
+ CommonSubExpressionCollector collector = new CommonSubExpressionCollector();
+ exprs.forEach(expr -> collector.collect(expr));
+
+ // a+b is at depth 1 and appears multiple times → should be in commonExprByDepth
+ Assertions.assertFalse(collector.commonExprByDepth.isEmpty(),
+ "a+b should be collected as common sub-expression");
+ Set<Expression> depth1 = collector.commonExprByDepth.get(1);
+ Assertions.assertNotNull(depth1, "common expressions at depth 1 should exist");
+ Assertions.assertEquals(1, depth1.size());
+ assertExpression(depth1.iterator().next(), "a+b");
+
+ // no WhenClause should appear in commonExprByDepth at any depth
+ for (Set<Expression> exprsAtDepth : collector.commonExprByDepth.values()) {
+ for (Expression e : exprsAtDepth) {
+ Assertions.assertFalse(e instanceof org.apache.doris.nereids.trees.expressions.WhenClause,
+ "WhenClause should not be collected as common sub-expression");
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyLayerWhenOnlyWhenClauseIsCommon() throws Exception {
+ // two identical WhenClause(false, null), no slot references
+ List<NamedExpression> exprs = parseProjections(
+ "CASE WHEN false THEN null WHEN false THEN null ELSE 1 END");
+ Set<Slot> inputSlots = new HashSet<>();
+
+ CommonSubExpressionOpt opt = new CommonSubExpressionOpt();
+ Method method = CommonSubExpressionOpt.class
+ .getDeclaredMethod("computeMultiLayerProjections", Set.class, List.class);
+ method.setAccessible(true);
+
+ List<List<NamedExpression>> multiLayers =
+ (List<List<NamedExpression>>) method.invoke(opt, inputSlots, exprs);
+
+ // Bug: multiLayers = [[], [CASE...]] — l0 is empty
+ // Expected: either multiLayers is empty (no useful CSE),
+ // or every layer is non-empty
+ for (List<NamedExpression> layer : multiLayers) {
+ Assertions.assertFalse(layer.isEmpty(),
+ "intermediate layer should not be empty");
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org