This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new ffcf01f4687 branch-3.1: [fix](Nereids) not generate duplicate exprid
after convert outer to anti rule #52798 (#53773)
ffcf01f4687 is described below
commit ffcf01f46876af4335fa73a1c6fc72e1acfc1bc9
Author: morrySnow <[email protected]>
AuthorDate: Fri Jul 25 17:45:10 2025 +0800
branch-3.1: [fix](Nereids) not generate duplicate exprid after convert
outer to anti rule #52798 (#53773)
cherry picked from #52798
---
.../doris/nereids/jobs/executor/Rewriter.java | 7 +-
.../org/apache/doris/nereids/rules/RuleSet.java | 2 -
.../rules/expression/ExpressionRewrite.java | 186 ++++++++++++++++++++-
.../rules/rewrite/ConvertOuterJoinToAntiJoin.java | 86 +++++++---
.../nereids/rules/rewrite/ExprIdRewriter.java | 184 --------------------
.../expressions/StatementScopeIdGenerator.java | 2 +-
.../trees/plans/logical/LogicalCTEConsumer.java | 17 ++
.../rewrite/ConvertOuterJoinToAntiJoinTest.java | 22 ++-
.../rules/rewrite/EliminateOuterJoinTest.java | 5 +-
.../rules/rewrite/SplitMultiDistinctTest.java | 76 +++++----
.../org/apache/doris/nereids/util/PlanChecker.java | 9 +
.../distinct_split/disitinct_split.out | Bin 9558 -> 9553 bytes
.../transform_outer_join_to_anti.groovy | 8 +
13 files changed, 342 insertions(+), 262 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java
index ec3a0ed2ec7..555f9dbca90 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java
@@ -49,6 +49,7 @@ import
org.apache.doris.nereids.rules.rewrite.CollectCteConsumerOutput;
import org.apache.doris.nereids.rules.rewrite.CollectFilterAboveConsumer;
import org.apache.doris.nereids.rules.rewrite.ColumnPruning;
import org.apache.doris.nereids.rules.rewrite.ConvertInnerOrCrossJoin;
+import org.apache.doris.nereids.rules.rewrite.ConvertOuterJoinToAntiJoin;
import org.apache.doris.nereids.rules.rewrite.CountDistinctRewrite;
import org.apache.doris.nereids.rules.rewrite.CountLiteralRewrite;
import org.apache.doris.nereids.rules.rewrite.CreatePartitionTopNFromWindow;
@@ -448,8 +449,7 @@ public class Rewriter extends AbstractBatchJobExecutor {
new CollectCteConsumerOutput()
)
),
- topic("Collect used column", custom(RuleType.COLLECT_COLUMNS,
QueryColumnCollector::new)
- )
+ topic("Collect used column", custom(RuleType.COLLECT_COLUMNS,
QueryColumnCollector::new))
)
);
@@ -457,6 +457,7 @@ public class Rewriter extends AbstractBatchJobExecutor {
ImmutableSet.of(LogicalCTEAnchor.class),
() -> jobs(
// after variant sub path pruning, we need do column pruning
again
+ bottomUp(RuleSet.PUSH_DOWN_FILTERS),
custom(RuleType.COLUMN_PRUNING, ColumnPruning::new),
bottomUp(ImmutableList.of(
new PushDownFilterThroughProject(),
@@ -550,6 +551,8 @@ public class Rewriter extends AbstractBatchJobExecutor {
topic("rewrite cte sub-tree before sub path push down",
custom(RuleType.REWRITE_CTE_CHILDREN, () ->
new RewriteCteChildren(beforePushDownJobs))
)));
+ rewriteJobs.addAll(jobs(topic("convert outer join to anti",
+ custom(RuleType.CONVERT_OUTER_JOIN_TO_ANTI,
ConvertOuterJoinToAntiJoin::new))));
if (needOrExpansion) {
rewriteJobs.addAll(jobs(topic("or expansion",
custom(RuleType.OR_EXPANSION, () ->
OrExpansion.INSTANCE))));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index bcd12ac17d2..15943a25a90 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -86,7 +86,6 @@ import
org.apache.doris.nereids.rules.implementation.LogicalTVFRelationToPhysica
import org.apache.doris.nereids.rules.implementation.LogicalTopNToPhysicalTopN;
import
org.apache.doris.nereids.rules.implementation.LogicalUnionToPhysicalUnion;
import
org.apache.doris.nereids.rules.implementation.LogicalWindowToPhysicalWindow;
-import org.apache.doris.nereids.rules.rewrite.ConvertOuterJoinToAntiJoin;
import org.apache.doris.nereids.rules.rewrite.CreatePartitionTopNFromWindow;
import org.apache.doris.nereids.rules.rewrite.EliminateFilter;
import org.apache.doris.nereids.rules.rewrite.EliminateOuterJoin;
@@ -148,7 +147,6 @@ public class RuleSet {
new PushDownFilterThroughGenerate(),
new PushDownProjectThroughLimit(),
new EliminateOuterJoin(),
- new ConvertOuterJoinToAntiJoin(),
new MergeProjects(),
new MergeFilters(),
new MergeGenerates(),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRewrite.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRewrite.java
index 376c22c7079..d8b9145727d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRewrite.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRewrite.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.rules.expression;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.pattern.ExpressionPatternRules;
import org.apache.doris.nereids.pattern.ExpressionPatternTraverseListeners;
+import org.apache.doris.nereids.pattern.MatchingContext;
import org.apache.doris.nereids.properties.OrderKey;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
@@ -28,26 +29,39 @@ import
org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
import org.apache.doris.nereids.trees.expressions.EqualPredicate;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.OrderExpression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.functions.Function;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalGenerate;
import org.apache.doris.nereids.trees.plans.logical.LogicalHaving;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPartitionTopN;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.trees.plans.logical.LogicalRepeat;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSetOperation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSink;
import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
+import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
import org.apache.doris.nereids.util.ExpressionUtils;
import org.apache.doris.nereids.util.Utils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -80,7 +94,19 @@ public class ExpressionRewrite implements RewriteRuleFactory
{
new JoinExpressionRewrite().build(),
new SortExpressionRewrite().build(),
new LogicalRepeatRewrite().build(),
- new HavingExpressionRewrite().build());
+ new HavingExpressionRewrite().build(),
+ new LogicalPartitionTopNExpressionRewrite().build(),
+ new LogicalTopNExpressionRewrite().build(),
+ new LogicalSetOperationRewrite().build(),
+ new LogicalWindowRewrite().build(),
+ new LogicalCteConsumerRewrite().build(),
+ new LogicalResultSinkRewrite().build(),
+ new LogicalFileSinkRewrite().build(),
+ new LogicalHiveTableSinkRewrite().build(),
+ new LogicalIcebergTableSinkRewrite().build(),
+ new LogicalJdbcTableSinkRewrite().build(),
+ new LogicalOlapTableSinkRewrite().build(),
+ new LogicalDeferMaterializeResultSinkRewrite().build());
}
/** GenerateExpressionRewrite */
@@ -278,6 +304,164 @@ public class ExpressionRewrite implements
RewriteRuleFactory {
}
}
+ private class LogicalWindowRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return logicalWindow().thenApply(ctx -> {
+ LogicalWindow<Plan> window = ctx.root;
+ List<NamedExpression> windowExpressions =
window.getWindowExpressions();
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ List<NamedExpression> result = rewriteAll(windowExpressions,
rewriter, context);
+ return window.withExpressionsAndChild(result, window.child());
+ })
+ .toRule(RuleType.REWRITE_WINDOW_EXPRESSION);
+ }
+ }
+
+ private class LogicalSetOperationRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return logicalSetOperation().thenApply(ctx -> {
+ LogicalSetOperation setOperation = ctx.root;
+ List<List<SlotReference>> slotsList =
setOperation.getRegularChildrenOutputs();
+ List<List<SlotReference>> newSlotsList = new ArrayList<>();
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ for (List<SlotReference> slots : slotsList) {
+ List<SlotReference> result = rewriteAll(slots, rewriter,
context);
+ newSlotsList.add(result);
+ }
+ return
setOperation.withChildrenAndTheirOutputs(setOperation.children(), newSlotsList);
+ })
+ .toRule(RuleType.REWRITE_SET_OPERATION_EXPRESSION);
+ }
+ }
+
+ private class LogicalTopNExpressionRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return logicalTopN().thenApply(ctx -> {
+ LogicalTopN<Plan> topN = ctx.root;
+ List<OrderKey> orderKeys = topN.getOrderKeys();
+ ImmutableList.Builder<OrderKey> rewrittenOrderKeys
+ =
ImmutableList.builderWithExpectedSize(orderKeys.size());
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ boolean changed = false;
+ for (OrderKey k : orderKeys) {
+ Expression expression = rewriter.rewrite(k.getExpr(),
context);
+ changed |= expression != k.getExpr();
+ rewrittenOrderKeys.add(new OrderKey(expression, k.isAsc(),
k.isNullFirst()));
+ }
+ return changed ?
topN.withOrderKeys(rewrittenOrderKeys.build()) : topN;
+ }).toRule(RuleType.REWRITE_TOPN_EXPRESSION);
+ }
+ }
+
+ private class LogicalPartitionTopNExpressionRewrite extends
OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return logicalPartitionTopN().thenApply(ctx -> {
+ LogicalPartitionTopN<Plan> partitionTopN = ctx.root;
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ List<OrderExpression> newOrderExpressions = new ArrayList<>();
+ for (OrderExpression orderExpression :
partitionTopN.getOrderKeys()) {
+ OrderKey orderKey = orderExpression.getOrderKey();
+ Expression expr = rewriter.rewrite(orderKey.getExpr(),
context);
+ OrderKey newOrderKey = new OrderKey(expr,
orderKey.isAsc(), orderKey.isNullFirst());
+ newOrderExpressions.add(new OrderExpression(newOrderKey));
+ }
+ List<Expression> result =
rewriteAll(partitionTopN.getPartitionKeys(), rewriter, context);
+ return partitionTopN.withPartitionKeysAndOrderKeys(result,
newOrderExpressions);
+ }).toRule(RuleType.REWRITE_PARTITION_TOPN_EXPRESSION);
+ }
+ }
+
+ private class LogicalCteConsumerRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return logicalCTEConsumer().thenApply(ctx -> {
+ LogicalCTEConsumer consumer = ctx.root;
+ boolean changed = false;
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ ImmutableMap.Builder<Slot, Slot> cToPBuilder =
ImmutableMap.builder();
+ ImmutableMultimap.Builder<Slot, Slot> pToCBuilder =
ImmutableMultimap.builder();
+ for (Map.Entry<Slot, Slot> entry :
consumer.getConsumerToProducerOutputMap().entrySet()) {
+ Slot key = (Slot) rewriter.rewrite(entry.getKey(),
context);
+ Slot value = (Slot) rewriter.rewrite(entry.getValue(),
context);
+ cToPBuilder.put(key, value);
+ pToCBuilder.put(value, key);
+ if (!key.equals(entry.getKey()) ||
!value.equals(entry.getValue())) {
+ changed = true;
+ }
+ }
+ return changed ? consumer.withTwoMaps(cToPBuilder.build(),
pToCBuilder.build()) : consumer;
+ }).toRule(RuleType.REWRITE_TOPN_EXPRESSION);
+ }
+ }
+
+ private class LogicalResultSinkRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalResultSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalFileSinkRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalFileSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalHiveTableSinkRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalHiveTableSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalIcebergTableSinkRewrite extends OneRewriteRuleFactory
{
+ @Override
+ public Rule build() {
+ return
logicalIcebergTableSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalJdbcTableSinkRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalJdbcTableSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalOlapTableSinkRewrite extends OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalOlapTableSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private class LogicalDeferMaterializeResultSinkRewrite extends
OneRewriteRuleFactory {
+ @Override
+ public Rule build() {
+ return
logicalDeferMaterializeResultSink().thenApply(ExpressionRewrite.this::applyRewriteToSink)
+ .toRule(RuleType.REWRITE_SINK_EXPRESSION);
+ }
+ }
+
+ private LogicalSink<Plan> applyRewriteToSink(MatchingContext<? extends
LogicalSink<Plan>> ctx) {
+ LogicalSink<Plan> sink = ctx.root;
+ ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
+ List<NamedExpression> outputExprs = sink.getOutputExprs();
+ List<NamedExpression> result = rewriteAll(outputExprs, rewriter,
context);
+ return sink.withOutputExprs(result);
+ }
+
/** LogicalRepeatRewrite */
public class LogicalRepeatRewrite extends OneRewriteRuleFactory {
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoin.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoin.java
index c9185fd1a3c..46445573055 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoin.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoin.java
@@ -17,9 +17,9 @@
package org.apache.doris.nereids.rules.rewrite;
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.jobs.JobContext;
import org.apache.doris.nereids.trees.expressions.Alias;
+import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
@@ -28,9 +28,14 @@ import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter;
+import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
import org.apache.doris.nereids.util.TypeUtils;
-import java.util.List;
+import com.google.common.collect.ImmutableList;
+
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -42,18 +47,41 @@ import java.util.stream.Collectors;
* project(A.*)
* - LeftAntiJoin(A, B)
*/
-public class ConvertOuterJoinToAntiJoin extends OneRewriteRuleFactory {
+public class ConvertOuterJoinToAntiJoin extends
DefaultPlanRewriter<Map<ExprId, ExprId>> implements CustomRewriter {
+ private ExprIdRewriter exprIdReplacer;
+
+ @Override
+ public Plan rewriteRoot(Plan plan, JobContext jobContext) {
+ if (!plan.containsType(LogicalJoin.class)) {
+ return plan;
+ }
+ Map<ExprId, ExprId> replaceMap = new HashMap<>();
+ ExprIdRewriter.ReplaceRule replaceRule = new
ExprIdRewriter.ReplaceRule(replaceMap);
+ exprIdReplacer = new ExprIdRewriter(replaceRule, jobContext);
+ return plan.accept(this, replaceMap);
+ }
@Override
- public Rule build() {
- return logicalFilter(logicalJoin()
- .when(join -> join.getJoinType().isOuterJoin()))
- .then(this::toAntiJoin)
- .toRule(RuleType.CONVERT_OUTER_JOIN_TO_ANTI);
+ public Plan visit(Plan plan, Map<ExprId, ExprId> replaceMap) {
+ plan = visitChildren(this, plan, replaceMap);
+ plan = exprIdReplacer.rewriteExpr(plan, replaceMap);
+ return plan;
}
- private Plan toAntiJoin(LogicalFilter<LogicalJoin<Plan, Plan>> filter) {
+ @Override
+ public Plan visitLogicalFilter(LogicalFilter<? extends Plan> filter,
Map<ExprId, ExprId> replaceMap) {
+ filter = (LogicalFilter<? extends Plan>) visit(filter, replaceMap);
+ if (!(filter.child() instanceof LogicalJoin)) {
+ return filter;
+ }
+ return toAntiJoin((LogicalFilter<LogicalJoin<Plan, Plan>>) filter,
replaceMap);
+ }
+
+ private Plan toAntiJoin(LogicalFilter<LogicalJoin<Plan, Plan>> filter,
Map<ExprId, ExprId> replaceMap) {
LogicalJoin<Plan, Plan> join = filter.child();
+ if (!join.getJoinType().isLeftOuterJoin() &&
!join.getJoinType().isRightOuterJoin()) {
+ return filter;
+ }
Set<Slot> alwaysNullSlots = filter.getConjuncts().stream()
.filter(p -> TypeUtils.isNull(p).isPresent())
@@ -66,33 +94,37 @@ public class ConvertOuterJoinToAntiJoin extends
OneRewriteRuleFactory {
.filter(s -> alwaysNullSlots.contains(s) && !s.nullable())
.collect(Collectors.toSet());
- Plan newJoin = null;
+ Plan newChild = null;
if (join.getJoinType().isLeftOuterJoin() &&
!rightAlwaysNullSlots.isEmpty()) {
- newJoin = join.withJoinTypeAndContext(JoinType.LEFT_ANTI_JOIN,
join.getJoinReorderContext());
+ newChild = join.withJoinTypeAndContext(JoinType.LEFT_ANTI_JOIN,
join.getJoinReorderContext());
}
if (join.getJoinType().isRightOuterJoin() &&
!leftAlwaysNullSlots.isEmpty()) {
- newJoin = join.withJoinTypeAndContext(JoinType.RIGHT_ANTI_JOIN,
join.getJoinReorderContext());
+ newChild = join.withJoinTypeAndContext(JoinType.RIGHT_ANTI_JOIN,
join.getJoinReorderContext());
}
- if (newJoin == null) {
- return null;
+ if (newChild == null) {
+ return filter;
}
- if (!newJoin.getOutputSet().containsAll(filter.getInputSlots())) {
+ if (!newChild.getOutputSet().containsAll(filter.getInputSlots())) {
// if there are slots that don't belong to join output, we use
null alias to replace them
// such as:
// project(A.id, null as B.id)
// - (A left anti join B)
- Set<Slot> joinOutput = newJoin.getOutputSet();
- List<NamedExpression> projects = filter.getOutput().stream()
- .map(s -> {
- if (joinOutput.contains(s)) {
- return s;
- } else {
- return new Alias(s.getExprId(), new
NullLiteral(s.getDataType()), s.getName());
- }
- }).collect(Collectors.toList());
- newJoin = new LogicalProject<>(projects, newJoin);
+ Set<Slot> joinOutputs = newChild.getOutputSet();
+ ImmutableList.Builder<NamedExpression> projectsBuilder =
ImmutableList.builder();
+ for (NamedExpression e : filter.getOutput()) {
+ if (joinOutputs.contains(e)) {
+ projectsBuilder.add(e);
+ } else {
+ Alias newAlias = new Alias(new
NullLiteral(e.getDataType()), e.getName(), e.getQualifier());
+ replaceMap.put(e.getExprId(), newAlias.getExprId());
+ projectsBuilder.add(newAlias);
+ }
+ }
+ newChild = new LogicalProject<>(projectsBuilder.build(), newChild);
+ return exprIdReplacer.rewriteExpr(filter.withChildren(newChild),
replaceMap);
+ } else {
+ return filter.withChildren(newChild);
}
- return filter.withChildren(newJoin);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
index 60c9da4bc6e..5e065fa3724 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
@@ -18,32 +18,20 @@
package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.nereids.jobs.JobContext;
-import org.apache.doris.nereids.pattern.MatchingContext;
import org.apache.doris.nereids.pattern.Pattern;
-import org.apache.doris.nereids.properties.OrderKey;
import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher;
import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory;
import org.apache.doris.nereids.rules.expression.ExpressionRewrite;
-import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.NamedExpression;
-import org.apache.doris.nereids.trees.expressions.OrderExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalPartitionTopN;
-import org.apache.doris.nereids.trees.plans.logical.LogicalSetOperation;
-import org.apache.doris.nereids.trees.plans.logical.LogicalSink;
-import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
-import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -58,26 +46,6 @@ public class ExprIdRewriter extends ExpressionRewrite {
this.jobContext = jobContext;
}
- @Override
- public List<Rule> buildRules() {
- ImmutableList.Builder<Rule> builder = ImmutableList.builder();
- builder.addAll(super.buildRules());
- builder.addAll(ImmutableList.of(
- new LogicalPartitionTopNExpressionRewrite().build(),
- new LogicalTopNExpressionRewrite().build(),
- new LogicalSetOperationRewrite().build(),
- new LogicalWindowRewrite().build(),
- new LogicalResultSinkRewrite().build(),
- new LogicalFileSinkRewrite().build(),
- new LogicalHiveTableSinkRewrite().build(),
- new LogicalIcebergTableSinkRewrite().build(),
- new LogicalJdbcTableSinkRewrite().build(),
- new LogicalOlapTableSinkRewrite().build(),
- new LogicalDeferMaterializeResultSinkRewrite().build()
- ));
- return builder.build();
- }
-
/**rewriteExpr*/
public Plan rewriteExpr(Plan plan, Map<ExprId, ExprId> replaceMap) {
if (replaceMap.isEmpty()) {
@@ -129,156 +97,4 @@ public class ExprIdRewriter extends ExpressionRewrite {
);
}
}
-
- private class LogicalResultSinkRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalResultSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalFileSinkRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalFileSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalHiveTableSinkRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalHiveTableSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalIcebergTableSinkRewrite extends OneRewriteRuleFactory
{
- @Override
- public Rule build() {
- return
logicalIcebergTableSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalJdbcTableSinkRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalJdbcTableSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalOlapTableSinkRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalOlapTableSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalDeferMaterializeResultSinkRewrite extends
OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return
logicalDeferMaterializeResultSink().thenApply(ExprIdRewriter.this::applyRewrite)
- .toRule(RuleType.REWRITE_SINK_EXPRESSION);
- }
- }
-
- private class LogicalSetOperationRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return logicalSetOperation().thenApply(ctx -> {
- LogicalSetOperation setOperation = ctx.root;
- List<List<SlotReference>> slotsList =
setOperation.getRegularChildrenOutputs();
- List<List<SlotReference>> newSlotsList = new ArrayList<>();
- ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
- for (List<SlotReference> slots : slotsList) {
- List<SlotReference> newSlots = rewriteAll(slots, rewriter,
context);
- newSlotsList.add(newSlots);
- }
- if (newSlotsList.equals(slotsList)) {
- return setOperation;
- }
- return
setOperation.withChildrenAndTheirOutputs(setOperation.children(), newSlotsList);
- })
- .toRule(RuleType.REWRITE_SET_OPERATION_EXPRESSION);
- }
- }
-
- private class LogicalWindowRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return logicalWindow().thenApply(ctx -> {
- LogicalWindow<Plan> window = ctx.root;
- List<NamedExpression> windowExpressions =
window.getWindowExpressions();
- ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
- List<NamedExpression> newWindowExpressions =
rewriteAll(windowExpressions, rewriter, context);
- if (newWindowExpressions.equals(windowExpressions)) {
- return window;
- }
- return window.withExpressionsAndChild(newWindowExpressions,
window.child());
- })
- .toRule(RuleType.REWRITE_WINDOW_EXPRESSION);
- }
- }
-
- private class LogicalTopNExpressionRewrite extends OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return logicalTopN().thenApply(ctx -> {
- LogicalTopN<Plan> topN = ctx.root;
- List<OrderKey> orderKeys = topN.getOrderKeys();
- ImmutableList.Builder<OrderKey> rewrittenOrderKeys
- =
ImmutableList.builderWithExpectedSize(orderKeys.size());
- ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
- boolean changed = false;
- for (OrderKey k : orderKeys) {
- Expression expression = rewriter.rewrite(k.getExpr(),
context);
- changed |= expression != k.getExpr();
- rewrittenOrderKeys.add(new OrderKey(expression, k.isAsc(),
k.isNullFirst()));
- }
- return changed ?
topN.withOrderKeys(rewrittenOrderKeys.build()) : topN;
- }).toRule(RuleType.REWRITE_TOPN_EXPRESSION);
- }
- }
-
- private class LogicalPartitionTopNExpressionRewrite extends
OneRewriteRuleFactory {
- @Override
- public Rule build() {
- return logicalPartitionTopN().thenApply(ctx -> {
- LogicalPartitionTopN<Plan> partitionTopN = ctx.root;
- ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
- List<OrderExpression> newOrderExpressions = new ArrayList<>();
- boolean changed = false;
- for (OrderExpression orderExpression :
partitionTopN.getOrderKeys()) {
- OrderKey orderKey = orderExpression.getOrderKey();
- Expression expr = rewriter.rewrite(orderKey.getExpr(),
context);
- changed |= expr != orderKey.getExpr();
- OrderKey newOrderKey = new OrderKey(expr,
orderKey.isAsc(), orderKey.isNullFirst());
- newOrderExpressions.add(new OrderExpression(newOrderKey));
- }
- List<Expression> newPartitionKeys =
rewriteAll(partitionTopN.getPartitionKeys(), rewriter, context);
- if
(!newPartitionKeys.equals(partitionTopN.getPartitionKeys())) {
- changed = true;
- }
- if (!changed) {
- return partitionTopN;
- }
- return
partitionTopN.withPartitionKeysAndOrderKeys(newPartitionKeys,
newOrderExpressions);
- }).toRule(RuleType.REWRITE_PARTITION_TOPN_EXPRESSION);
- }
- }
-
- private LogicalSink<Plan> applyRewrite(MatchingContext<? extends
LogicalSink<Plan>> ctx) {
- LogicalSink<Plan> sink = ctx.root;
- ExpressionRewriteContext context = new
ExpressionRewriteContext(ctx.cascadesContext);
- List<NamedExpression> outputExprs = sink.getOutputExprs();
- List<NamedExpression> newOutputExprs = rewriteAll(outputExprs,
rewriter, context);
- if (outputExprs.equals(newOutputExprs)) {
- return sink;
- }
- return sink.withOutputExprs(newOutputExprs);
- }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/StatementScopeIdGenerator.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/StatementScopeIdGenerator.java
index df7ef2ab69a..cf0ecc3cb9b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/StatementScopeIdGenerator.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/StatementScopeIdGenerator.java
@@ -81,6 +81,6 @@ public class StatementScopeIdGenerator {
if (ConnectContext.get() != null) {
ConnectContext.get().setStatementContext(new StatementContext());
}
- statementContext = new StatementContext();
+ statementContext = new StatementContext(10000);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTEConsumer.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTEConsumer.java
index 2941392ea71..7c1079935a1 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTEConsumer.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTEConsumer.java
@@ -199,4 +199,21 @@ public class LogicalCTEConsumer extends LogicalRelation
implements BlockFuncDeps
"relationId", relationId,
"name", name);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ LogicalCTEConsumer that = (LogicalCTEConsumer) o;
+ return Objects.equals(consumerToProducerOutputMap,
that.consumerToProducerOutputMap);
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoinTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoinTest.java
index 1159fc2a7ce..b3166c22240 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoinTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ConvertOuterJoinToAntiJoinTest.java
@@ -32,17 +32,21 @@ import
org.apache.doris.nereids.util.MemoPatternMatchSupported;
import org.apache.doris.nereids.util.MemoTestUtils;
import org.apache.doris.nereids.util.PlanChecker;
import org.apache.doris.nereids.util.PlanConstructor;
+import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ConvertOuterJoinToAntiJoinTest implements MemoPatternMatchSupported {
- private final LogicalOlapScan scan1;
- private final LogicalOlapScan scan2;
+ private LogicalOlapScan scan1;
+ private LogicalOlapScan scan2;
- public ConvertOuterJoinToAntiJoinTest() throws Exception {
+ @BeforeEach
+ void setUp() throws Exception {
// clear id so that slot id keep consistent every running
+ ConnectContext.remove();
StatementScopeIdGenerator.clear();
scan1 = PlanConstructor.newLogicalOlapScan(0, "t1", 0);
scan2 = PlanConstructor.newLogicalOlapScan(1, "t2", 0);
@@ -58,7 +62,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isLeftAntiJoin()));
}
@@ -73,7 +77,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isRightAntiJoin()));
}
@@ -91,7 +95,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isLeftAntiJoin()));
}
@@ -109,7 +113,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isLeftAntiJoin()));
}
@@ -127,7 +131,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isLeftOuterJoin()));
}
@@ -146,7 +150,7 @@ class ConvertOuterJoinToAntiJoinTest implements
MemoPatternMatchSupported {
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyTopDown(new InferFilterNotNull())
- .applyTopDown(new ConvertOuterJoinToAntiJoin())
+ .applyCustom(new ConvertOuterJoinToAntiJoin())
.printlnTree()
.matches(logicalJoin().when(join ->
join.getJoinType().isLeftOuterJoin()));
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoinTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoinTest.java
index 255f1e82e00..f0034410163 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoinTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoinTest.java
@@ -21,6 +21,7 @@ import org.apache.doris.common.Pair;
import org.apache.doris.nereids.trees.expressions.And;
import org.apache.doris.nereids.trees.expressions.GreaterThan;
import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
@@ -69,7 +70,7 @@ class EliminateOuterJoinTest implements
MemoPatternMatchSupported {
void testEliminateRight() {
LogicalPlan plan = new LogicalPlanBuilder(scan1)
.join(scan2, JoinType.RIGHT_OUTER_JOIN, Pair.of(0, 0)) //
t1.id = t2.id
- .filter(new GreaterThan(scan1.getOutput().get(0),
Literal.of(1)))
+ .filter(new GreaterThan(scan1.getOutput().get(0), new
IntegerLiteral(1)))
.build();
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
@@ -81,7 +82,7 @@ class EliminateOuterJoinTest implements
MemoPatternMatchSupported {
logicalFilter(
logicalJoin().when(join ->
join.getJoinType().isInnerJoin())
).when(filter -> filter.getConjuncts().size() == 1)
- .when(filter ->
Objects.equals(filter.getConjuncts().toString(), "[(id#0 > 1)]"))
+ .when(filter ->
Objects.equals(filter.getConjuncts().iterator().next(), new
GreaterThan(scan1.getOutput().get(0), new IntegerLiteral(1))))
);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/SplitMultiDistinctTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/SplitMultiDistinctTest.java
index ebc6331506a..acadb01e759 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/SplitMultiDistinctTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/SplitMultiDistinctTest.java
@@ -46,23 +46,25 @@ public class SplitMultiDistinctTest extends
TestWithFeService implements MemoPat
physicalCTEAnchor(
physicalCTEProducer(any()),
physicalResultSink(
- physicalProject(
+
physicalNestedLoopJoin(
+ physicalProject(
physicalHashAggregate(
physicalDistribute(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))))),
+
physicalHashAggregate(any()))))))),
physicalDistribute(
+ physicalProject(
physicalHashAggregate(
physicalDistribute(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))))))
+
physicalHashAggregate(any()))))))))
)
- )
+
)
)
);
@@ -78,23 +80,25 @@ public class SplitMultiDistinctTest extends
TestWithFeService implements MemoPat
physicalCTEAnchor(
physicalCTEProducer(any()),
physicalResultSink(
- physicalProject(
+
physicalNestedLoopJoin(
+ physicalProject(
physicalHashAggregate(
physicalDistribute(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))))),
+
physicalHashAggregate(any()))))))),
physicalDistribute(
+ physicalProject(
physicalHashAggregate(
physicalDistribute(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))))))
+
physicalHashAggregate(any()))))))))
)
- )
+
)
)
);
@@ -108,26 +112,26 @@ public class SplitMultiDistinctTest extends
TestWithFeService implements MemoPat
Plan plan = planner.getOptimizedPlan();
MatchingUtils.assertMatches(plan,
physicalCTEAnchor(
- physicalCTEProducer(any()),
- physicalResultSink(
- physicalProject(
- physicalNestedLoopJoin(
- physicalHashAggregate(
- physicalDistribute(
-
physicalHashAggregate(
-
physicalHashAggregate(
-
physicalDistribute(
-
physicalHashAggregate(any())))))),
- physicalDistribute(
-
physicalHashAggregate(
-
physicalDistribute(
-
physicalHashAggregate(
-
physicalHashAggregate(
-
physicalDistribute(
-
physicalHashAggregate(any())))))))
- )
- )
- )
+ physicalCTEProducer(any()),
+ physicalResultSink(
+ physicalNestedLoopJoin(
+ physicalProject(
+ physicalHashAggregate(
+ physicalDistribute(
+ physicalHashAggregate(
+ physicalHashAggregate(
+ physicalDistribute(
+
physicalHashAggregate(any()))))))),
+ physicalDistribute(
+ physicalProject(
+ physicalHashAggregate(
+ physicalDistribute(
+ physicalHashAggregate(
+ physicalHashAggregate(
+
physicalDistribute(
+
physicalHashAggregate(any()))))))))
+ )
+ )
)
);
});
@@ -142,19 +146,21 @@ public class SplitMultiDistinctTest extends
TestWithFeService implements MemoPat
physicalCTEAnchor(
physicalCTEProducer(any()),
physicalResultSink(
- physicalProject(
+
physicalNestedLoopJoin(
+ physicalProject(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))),
+
physicalHashAggregate(any()))))),
physicalDistribute(
+ physicalProject(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))))
+
physicalHashAggregate(any()))))))
)
- )
+
)
)
);
@@ -174,14 +180,16 @@ public class SplitMultiDistinctTest extends
TestWithFeService implements MemoPat
physicalDistribute(
physicalProject(
physicalHashJoin(
+ physicalProject(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any())))),
+
physicalHashAggregate(any()))))),
+ physicalProject(
physicalHashAggregate(
physicalHashAggregate(
physicalDistribute(
-
physicalHashAggregate(any()))))
+
physicalHashAggregate(any())))))
).when(join ->
join.getJoinType() ==
JoinType.INNER_JOIN && join.getHashJoinConjuncts().get(0) instanceof
NullSafeEqual
)
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
index 71d0f0101b0..6962572d07a 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob;
import org.apache.doris.nereids.jobs.executor.Optimizer;
import org.apache.doris.nereids.jobs.executor.Rewriter;
import org.apache.doris.nereids.jobs.joinorder.JoinOrderJob;
+import org.apache.doris.nereids.jobs.rewrite.CustomRewriteJob;
import org.apache.doris.nereids.jobs.rewrite.PlanTreeRewriteBottomUpJob;
import org.apache.doris.nereids.jobs.rewrite.PlanTreeRewriteTopDownJob;
import org.apache.doris.nereids.jobs.rewrite.RootPlanTreeRewriteJob;
@@ -202,6 +203,14 @@ public class PlanChecker {
return this;
}
+ public PlanChecker applyCustom(CustomRewriter customRewriter) {
+ CustomRewriteJob customRewriteJob = new CustomRewriteJob(() ->
customRewriter, RuleType.TEST_REWRITE);
+ customRewriteJob.execute(cascadesContext.getCurrentJobContext());
+ cascadesContext.toMemo();
+ MemoValidator.validate(cascadesContext.getMemo());
+ return this;
+ }
+
/**
* apply a top down rewrite rule if you not care the ruleId
*
diff --git
a/regression-test/data/nereids_rules_p0/distinct_split/disitinct_split.out
b/regression-test/data/nereids_rules_p0/distinct_split/disitinct_split.out
index a0aff0a9a19..ede0fb5259c 100644
Binary files
a/regression-test/data/nereids_rules_p0/distinct_split/disitinct_split.out and
b/regression-test/data/nereids_rules_p0/distinct_split/disitinct_split.out
differ
diff --git
a/regression-test/suites/nereids_syntax_p0/transform_outer_join_to_anti.groovy
b/regression-test/suites/nereids_syntax_p0/transform_outer_join_to_anti.groovy
index ccbb8fd64a8..f806f4ce5c7 100644
---
a/regression-test/suites/nereids_syntax_p0/transform_outer_join_to_anti.groovy
+++
b/regression-test/suites/nereids_syntax_p0/transform_outer_join_to_anti.groovy
@@ -84,4 +84,12 @@ suite("transform_outer_join_to_anti") {
sql("select * from eliminate_outer_join_A right outer join
eliminate_outer_join_B on eliminate_outer_join_B.b = eliminate_outer_join_A.a
where eliminate_outer_join_A.a is null and eliminate_outer_join_B.null_b is
null and eliminate_outer_join_A.null_a is null")
contains "ANTI JOIN"
}
+
+ explain {
+ sql """with temp as (
+ select * from eliminate_outer_join_A left outer join
eliminate_outer_join_B on eliminate_outer_join_B.b = eliminate_outer_join_A.a
where eliminate_outer_join_B.b is null
+ )
+ select * from temp t1 join temp t2"""
+ contains "ANTI JOIN"
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]