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 d604b45beba branch-3.1: [fix](nereids) pull up left join right
predicate with or is null #58372 (#58664)
d604b45beba is described below
commit d604b45bebaf908f45bfd5e710253dab3bbd5545
Author: feiniaofeiafei <[email protected]>
AuthorDate: Thu Dec 4 17:13:34 2025 +0800
branch-3.1: [fix](nereids) pull up left join right predicate with or is
null #58372 (#58664)
picked from #58372
---
.../rules/rewrite/InferPredicateByReplace.java | 9 ++
.../nereids/rules/rewrite/InferPredicates.java | 104 +++++++++++++++---
.../nereids/rules/rewrite/PullUpPredicates.java | 33 ++++++
.../trees/expressions/CompoundPredicate.java | 6 +-
.../apache/doris/nereids/trees/expressions/Or.java | 22 +++-
.../trees/plans/logical/LogicalAggregate.java | 2 +-
.../rules/rewrite/InferPredicateByReplaceTest.java | 2 +-
.../apache/doris/nereids/sqltest/InferTest.java | 10 +-
.../extend_infer_equal_predicate.out | 119 ++++++++++++++++++++-
.../extend_infer_equal_predicate.groovy | 39 ++++++-
10 files changed, 319 insertions(+), 27 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java
index 4fc9efc1943..ce5c90b75a4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java
@@ -29,6 +29,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.InPredicate;
import org.apache.doris.nereids.trees.expressions.Like;
import org.apache.doris.nereids.trees.expressions.Not;
+import org.apache.doris.nereids.trees.expressions.Or;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
@@ -127,6 +128,14 @@ public class InferPredicateByReplace {
return null;
}
+ @Override
+ public Void visitOr(Or or, Map<Expression, Set<Expression>> context) {
+ for (Expression expr : getAllSubExpressions(or)) {
+ context.computeIfAbsent(expr, k -> new
LinkedHashSet<>()).add(or);
+ }
+ return null;
+ }
+
private boolean validComparisonPredicate(ComparisonPredicate
comparisonPredicate) {
return comparisonPredicate.right() instanceof Literal;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicates.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicates.java
index 4ca9cfad478..07852d5274b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicates.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicates.java
@@ -18,9 +18,12 @@
package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.mysql.MysqlCommand;
+import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.jobs.JobContext;
import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.IsNull;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.Or;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
@@ -37,15 +40,20 @@ import org.apache.doris.nereids.util.PlanUtils;
import org.apache.doris.nereids.util.PredicateInferUtils;
import org.apache.doris.qe.ConnectContext;
+import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Supplier;
/**
* infer additional predicates for `LogicalFilter` and `LogicalJoin`.
@@ -89,20 +97,23 @@ public class InferPredicates extends
DefaultPlanRewriter<JobContext> implements
Plan right = join.right();
Set<Expression> expressions = getAllExpressions(left, right,
join.getOnClauseCondition());
switch (join.getJoinType()) {
- case INNER_JOIN:
case CROSS_JOIN:
- case LEFT_SEMI_JOIN:
- case RIGHT_SEMI_JOIN:
left = inferNewPredicate(left, expressions);
right = inferNewPredicate(right, expressions);
break;
+ case INNER_JOIN:
+ case LEFT_SEMI_JOIN:
+ case RIGHT_SEMI_JOIN:
+ left = inferNewPredicateRemoveUselessIsNull(left, expressions,
join, context.getCascadesContext());
+ right = inferNewPredicateRemoveUselessIsNull(right,
expressions, join, context.getCascadesContext());
+ break;
case LEFT_OUTER_JOIN:
case LEFT_ANTI_JOIN:
- right = inferNewPredicate(right, expressions);
+ right = inferNewPredicateRemoveUselessIsNull(right,
expressions, join, context.getCascadesContext());
break;
case RIGHT_OUTER_JOIN:
case RIGHT_ANTI_JOIN:
- left = inferNewPredicate(left, expressions);
+ left = inferNewPredicateRemoveUselessIsNull(left, expressions,
join, context.getCascadesContext());
break;
default:
break;
@@ -120,9 +131,16 @@ public class InferPredicates extends
DefaultPlanRewriter<JobContext> implements
return new
LogicalEmptyRelation(StatementScopeIdGenerator.newRelationId(),
filter.getOutput());
}
filter = visitChildren(this, filter, context);
- Set<Expression> filterPredicates = pullUpPredicates(filter);
- filterPredicates.removeAll(pullUpAllPredicates(filter.child()));
- return new LogicalFilter<>(ImmutableSet.copyOf(filterPredicates),
filter.child());
+ Set<Expression> inferredPredicates = pullUpPredicates(filter);
+ inferredPredicates.removeAll(pullUpAllPredicates(filter.child()));
+ if (inferredPredicates.isEmpty()) {
+ return filter.child();
+ }
+ if (inferredPredicates.equals(filter.getConjuncts())) {
+ return filter;
+ } else {
+ return new
LogicalFilter<>(ImmutableSet.copyOf(inferredPredicates), filter.child());
+ }
}
@Override
@@ -134,15 +152,18 @@ public class InferPredicates extends
DefaultPlanRewriter<JobContext> implements
}
ImmutableList.Builder<Plan> builder = ImmutableList.builder();
builder.add(except.child(0));
+ boolean changed = false;
for (int i = 1; i < except.arity(); ++i) {
Map<Expression, Expression> replaceMap = new HashMap<>();
for (int j = 0; j < except.getOutput().size(); ++j) {
NamedExpression output = except.getOutput().get(j);
replaceMap.put(output, except.getRegularChildOutput(i).get(j));
}
- builder.add(inferNewPredicate(except.child(i),
ExpressionUtils.replace(baseExpressions, replaceMap)));
+ Plan newChild = inferNewPredicate(except.child(i),
ExpressionUtils.replace(baseExpressions, replaceMap));
+ changed = changed || newChild != except.child(i);
+ builder.add(newChild);
}
- return except.withChildren(builder.build());
+ return changed ? except.withChildren(builder.build()) : except;
}
@Override
@@ -153,15 +174,18 @@ public class InferPredicates extends
DefaultPlanRewriter<JobContext> implements
return intersect;
}
ImmutableList.Builder<Plan> builder = ImmutableList.builder();
+ boolean changed = false;
for (int i = 0; i < intersect.arity(); ++i) {
Map<Expression, Expression> replaceMap = new HashMap<>();
for (int j = 0; j < intersect.getOutput().size(); ++j) {
NamedExpression output = intersect.getOutput().get(j);
replaceMap.put(output,
intersect.getRegularChildOutput(i).get(j));
}
- builder.add(inferNewPredicate(intersect.child(i),
ExpressionUtils.replace(baseExpressions, replaceMap)));
+ Plan newChild = inferNewPredicate(intersect.child(i),
ExpressionUtils.replace(baseExpressions, replaceMap));
+ changed = changed || newChild != intersect.child(i);
+ builder.add(newChild);
}
- return intersect.withChildren(builder.build());
+ return changed ? intersect.withChildren(builder.build()) : intersect;
}
private Set<Expression> getAllExpressions(Plan left, Plan right,
Optional<Expression> condition) {
@@ -191,4 +215,60 @@ public class InferPredicates extends
DefaultPlanRewriter<JobContext> implements
predicates.removeAll(plan.accept(pullUpAllPredicates, null));
return PlanUtils.filterOrSelf(predicates, plan);
}
+
+ // Remove redundant "or is null" from expressions.
+ // For example, when we have a t2 left join t3 condition t2.a=t3.a, we can
infer that t3.a is not null.
+ // If we find a predicate like "t3.a = 1 or t3.a is null" in expressions,
we change it to "t3.a=1".
+ private Plan inferNewPredicateRemoveUselessIsNull(Plan plan,
Set<Expression> expressions,
+ LogicalJoin<? extends Plan, ? extends Plan> join, CascadesContext
cascadesContext) {
+ Supplier<Set<Slot>> supplier = Suppliers.memoize(() -> {
+ Set<Expression> all = new HashSet<>();
+ all.addAll(join.getHashJoinConjuncts());
+ all.addAll(join.getOtherJoinConjuncts());
+ return ExpressionUtils.inferNotNullSlots(all, cascadesContext);
+ });
+
+ Set<Expression> predicates = new LinkedHashSet<>();
+ Set<Slot> planOutputs = plan.getOutputSet();
+ for (Expression expr : expressions) {
+ Set<Slot> slots = expr.getInputSlots();
+ if (slots.isEmpty() || !planOutputs.containsAll(slots)) {
+ continue;
+ }
+ if (expr instanceof Or && expr.isInferred()) {
+ List<Expression> orChildren =
ExpressionUtils.extractDisjunction(expr);
+ List<Expression> newOrChildren = Lists.newArrayList();
+ boolean changed = false;
+ for (Expression orChild : orChildren) {
+ if (orChild instanceof IsNull && orChild.child(0)
instanceof Slot
+ && supplier.get().contains(orChild.child(0))) {
+ changed = true;
+ continue;
+ }
+ newOrChildren.add(orChild);
+ }
+ if (changed) {
+ if (newOrChildren.size() == 1) {
+
predicates.add(withInferredIfSupported(newOrChildren.get(0), expr));
+ } else if (newOrChildren.size() > 1) {
+
predicates.add(ExpressionUtils.or(newOrChildren).withInferred(true));
+ }
+ } else {
+ predicates.add(expr);
+ }
+ } else {
+ predicates.add(expr);
+ }
+ }
+ predicates.removeAll(plan.accept(pullUpAllPredicates, null));
+ return PlanUtils.filterOrSelf(predicates, plan);
+ }
+
+ private Expression withInferredIfSupported(Expression expression,
Expression originExpr) {
+ try {
+ return expression.withInferred(true);
+ } catch (RuntimeException e) {
+ return originExpr;
+ }
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PullUpPredicates.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PullUpPredicates.java
index 57d3b0dc4e4..23950c48e3c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PullUpPredicates.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PullUpPredicates.java
@@ -53,6 +53,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
@@ -246,6 +247,10 @@ public class PullUpPredicates extends
PlanVisitor<ImmutableSet<Expression>, Void
break;
}
case LEFT_OUTER_JOIN:
+ predicates.addAll(leftPredicates.get());
+ predicates.addAll(
+
generateNullTolerantPredicates(rightPredicates.get(),
join.right().getOutputSet()));
+ break;
case LEFT_SEMI_JOIN:
case LEFT_ANTI_JOIN:
case NULL_AWARE_LEFT_ANTI_JOIN: {
@@ -253,6 +258,10 @@ public class PullUpPredicates extends
PlanVisitor<ImmutableSet<Expression>, Void
break;
}
case RIGHT_OUTER_JOIN:
+ predicates.addAll(rightPredicates.get());
+ predicates.addAll(
+
generateNullTolerantPredicates(leftPredicates.get(),
join.left().getOutputSet()));
+ break;
case RIGHT_SEMI_JOIN:
case RIGHT_ANTI_JOIN: {
predicates.addAll(rightPredicates.get());
@@ -346,6 +355,30 @@ public class PullUpPredicates extends
PlanVisitor<ImmutableSet<Expression>, Void
return expression.anyMatch(AggregateFunction.class::isInstance);
}
+ private Set<Expression> generateNullTolerantPredicates(Set<Expression>
predicates, Set<Slot> nullableSlots) {
+ if (predicates.isEmpty() || nullableSlots.isEmpty()) {
+ return predicates;
+ }
+ Set<Expression> tolerant =
Sets.newLinkedHashSetWithExpectedSize(predicates.size());
+ for (Expression predicate : predicates) {
+ Set<Slot> predicateSlots = predicate.getInputSlots();
+ List<Expression> orChildren = new ArrayList<>();
+ if (predicateSlots.size() == 1) {
+ Slot slot = predicateSlots.iterator().next();
+ if (nullableSlots.contains(slot)) {
+ orChildren.add(new IsNull(slot));
+ }
+ }
+ if (!orChildren.isEmpty()) {
+ List<Expression> expandedOr = new ArrayList<>(2);
+ expandedOr.add(predicate);
+ expandedOr.addAll(orChildren);
+ tolerant.add(ExpressionUtils.or(expandedOr));
+ }
+ }
+ return tolerant;
+ }
+
private ImmutableSet<Expression> getFiltersFromUnionChild(LogicalUnion
union, Void context) {
Set<Expression> filters = new LinkedHashSet<>();
for (int i = 0; i < union.getArity(); ++i) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java
index 9b1535eb9cc..3e04ee53d90 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java
@@ -37,7 +37,11 @@ public abstract class CompoundPredicate extends Expression
implements ExpectsInp
private String symbol;
public CompoundPredicate(List<Expression> children, String symbol) {
- super(children);
+ this(children, symbol, false);
+ }
+
+ public CompoundPredicate(List<Expression> children, String symbol, boolean
inferred) {
+ super(children, inferred);
this.symbol = symbol;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java
index cf6c46c3ea4..b62c0e76b40 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java
@@ -36,19 +36,28 @@ public class Or extends CompoundPredicate {
* @param right right child of comparison predicate
*/
public Or(Expression left, Expression right) {
- super(ExpressionUtils.mergeList(
+ this(left, right, false);
+ }
+
+ public Or(Expression left, Expression right, boolean inferred) {
+ this(ExpressionUtils.mergeList(
ExpressionUtils.extractDisjunction(left),
- ExpressionUtils.extractDisjunction(right)), "OR");
+ ExpressionUtils.extractDisjunction(right)), inferred);
}
public Or(List<Expression> children) {
- super(children, "OR");
+ this(children, false);
+ }
+
+ public Or(List<Expression> children, boolean inferred) {
+ super(children, "OR", inferred);
+ Preconditions.checkArgument(children.size() >= 2);
}
@Override
public Expression withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() >= 2);
- return new Or(children);
+ return new Or(children, this.isInferred());
}
@Override
@@ -89,4 +98,9 @@ public class Or extends CompoundPredicate {
}
return flattenChildren;
}
+
+ @Override
+ public Expression withInferred(boolean inferred) {
+ return new Or(children, inferred);
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
index fbea327f7a8..fd224426c2c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
@@ -284,7 +284,7 @@ public class LogicalAggregate<CHILD_TYPE extends Plan>
public LogicalAggregate<Plan>
withChildGroupByAndOutputAndSourceRepeat(List<Expression> groupByExprList,
List<NamedExpression> outputExpressionList, Plan newChild,
-
Optional<LogicalRepeat<?>> sourceRepeat) {
+
Optional<LogicalRepeat<? extends Plan>> sourceRepeat) {
return new LogicalAggregate<>(groupByExprList, outputExpressionList,
normalized, ordinalIsResolved, generated,
hasPushed, sourceRepeat, Optional.empty(), Optional.empty(),
newChild);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
index 98fbbfbec13..ad35028d7b9 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
@@ -152,7 +152,7 @@ public class InferPredicateByReplaceTest {
inputs.add(equalTo);
Set<Expression> result = InferPredicateByReplace.infer(inputs);
- Assertions.assertEquals(2, result.size());
+ Assertions.assertEquals(3, result.size());
}
@Test
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/InferTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/InferTest.java
index 613965b1238..d7853012e6f 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/InferTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/InferTest.java
@@ -49,9 +49,10 @@ public class InferTest extends SqlTestBase {
.printlnTree()
.matches(
innerLogicalJoin(
- logicalOlapScan(),
- logicalFilter().when(
- f ->
f.getPredicate().toString().equals("OR[(id#0 = 4),(id#0 > 4)]"))
+ logicalFilter().when(
+ f ->
f.getPredicate().toString().equals("OR[(id#2 = 4),(id#2 > 4)]")),
+ logicalFilter().when(
+ f ->
f.getPredicate().toString().equals("OR[(id#0 = 4),(id#0 > 4)]"))
)
);
@@ -70,7 +71,8 @@ public class InferTest extends SqlTestBase {
leftOuterLogicalJoin(
logicalFilter().when(
f ->
f.getPredicate().toString().equals("OR[(id#0 = 4),(id#0 > 4)]")),
- logicalOlapScan()
+ logicalFilter().when(
+ f ->
f.getPredicate().toString().equals("OR[(id#2 = 4),(id#2 > 4)]"))
)
).when(f -> f.getPredicate().toString()
.equals("OR[(id#0 = 4),AND[(id#0 > 4),score#3
IS NULL]]"))
diff --git
a/regression-test/data/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.out
b/regression-test/data/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.out
index ed43d254b50..7ec049b663c 100644
---
a/regression-test/data/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.out
+++
b/regression-test/data/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.out
@@ -114,14 +114,16 @@ PhysicalResultSink
--hashJoin[INNER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
----filter(OR[(t1.a < 2),(t1.a > 10)])
------PhysicalOlapScan[extend_infer_t3]
-----PhysicalOlapScan[extend_infer_t4]
+----filter(OR[(t2.a < 2),(t2.a > 10)])
+------PhysicalOlapScan[extend_infer_t4]
-- !test_or2 --
PhysicalResultSink
--hashJoin[INNER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
----filter(OR[(t1.a < 2),(t1.a > 10)])
------PhysicalOlapScan[extend_infer_t3]
-----PhysicalOlapScan[extend_infer_t4]
+----filter(OR[(t2.a < 2),(t2.a > 10)])
+------PhysicalOlapScan[extend_infer_t4]
-- !test_sign_predicate --
PhysicalResultSink
@@ -771,3 +773,116 @@ PhysicalResultSink
-- !pull_up_from_agg --
0
+-- !qt_leftjoin_right_pull_up_shape_shape --
+PhysicalResultSink
+--hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter((t1.a = 1))
+--------PhysicalOlapScan[extend_infer_t3]
+------filter((t2.a = 1))
+--------PhysicalOlapScan[extend_infer_t4]
+----filter((t3.a = 1))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_leftjoin_right_pull_up_shape_result --
+
+-- !qt_multi_leftjoin_right_pull_up_shape_shape --
+PhysicalResultSink
+--hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t5.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t4.a = t3.a)) otherCondition=()
+------hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+--------hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a))
otherCondition=()
+----------filter((t1.a = 1))
+------------PhysicalOlapScan[extend_infer_t3]
+----------filter((t2.a = 1))
+------------PhysicalOlapScan[extend_infer_t4]
+--------filter((t3.a = 1))
+----------PhysicalOlapScan[extend_infer_t5]
+------filter((t4.a = 1))
+--------PhysicalOlapScan[extend_infer_t5]
+----filter((t5.a = 1))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_multi_leftjoin_right_pull_up_shape_result --
+
+-- !qt_leftjoin_right_pull_up_in_shape_shape --
+PhysicalResultSink
+--hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter(a IN (1, 2))
+--------PhysicalOlapScan[extend_infer_t3]
+------filter(a IN (1, 2))
+--------PhysicalOlapScan[extend_infer_t4]
+----filter(a IN (1, 2))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_leftjoin_right_pull_up_in_shape_result --
+
+-- !qt_leftjoin_right_pull_up_is_null_shape_shape --
+PhysicalResultSink
+--hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter(a IS NULL)
+--------PhysicalOlapScan[extend_infer_t3]
+------PhysicalOlapScan[extend_infer_t4]
+----PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_leftjoin_right_pull_up_is_null_shape_result --
+\N \N 9 3 \N \N \N \N \N \N
\N \N
+\N d2 3 55 \N \N \N \N \N \N
\N \N
+
+-- !qt_leftjoin_right_pull_up_is_not_null_shape_shape --
+PhysicalResultSink
+--hashJoin[LEFT_OUTER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter(( not a IS NULL))
+--------PhysicalOlapScan[extend_infer_t3]
+------PhysicalOlapScan[extend_infer_t4]
+----PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_leftjoin_right_pull_up_is_not_null_shape_result --
+0 d2 3 5 0 d2 2 2 \N \N
\N \N
+100 d2 3 5 100 d2 3 \N \N \N
\N \N
+12 \N 9 3 \N \N \N \N \N \N
\N \N
+33 d2 2 5 33 d2 23 5 \N \N
\N \N
+78 \N 9 3 78 d2 23 5 \N \N
\N \N
+
+-- !qt_left_join_inner_shape --
+PhysicalResultSink
+--hashJoin[INNER_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[INNER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter((t1.a = 1))
+--------PhysicalOlapScan[extend_infer_t3]
+------filter((t2.a = 1))
+--------PhysicalOlapScan[extend_infer_t4]
+----filter((t3.a = 1))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_left_join_inner_result --
+
+-- !qt_left_join_semi_shape --
+PhysicalResultSink
+--hashJoin[LEFT_SEMI_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[INNER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter((t1.a = 1))
+--------PhysicalOlapScan[extend_infer_t3]
+------filter((t2.a = 1))
+--------PhysicalOlapScan[extend_infer_t4]
+----filter((t3.a = 1))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_left_join_semi_result --
+
+-- !qt_left_join_anti_shape --
+PhysicalResultSink
+--hashJoin[LEFT_ANTI_JOIN] hashCondition=((t2.a = t3.a)) otherCondition=()
+----hashJoin[LEFT_OUTER_JOIN] hashCondition=((t1.a = t2.a)) otherCondition=()
+------filter((t1.a = 1))
+--------PhysicalOlapScan[extend_infer_t3]
+------filter((t2.a = 1))
+--------PhysicalOlapScan[extend_infer_t4]
+----filter((t3.a = 1))
+------PhysicalOlapScan[extend_infer_t5]
+
+-- !qt_left_join_anti_result --
+
diff --git
a/regression-test/suites/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.groovy
b/regression-test/suites/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.groovy
index b7a6090e901..3c93815ce6a 100644
---
a/regression-test/suites/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.groovy
+++
b/regression-test/suites/nereids_rules_p0/infer_predicate/extend_infer_equal_predicate.groovy
@@ -357,8 +357,8 @@ suite("extend_infer_equal_predicate") {
qt_pull_up_window_order_column """select c1,a from (select a,b,sum(a)
over(order by a) c1 from extend_infer_t3 where a<33 ) t where a<33 order by
1,2"""
qt_pull_up_partition_topn """select * from (select a, c,row_number()
over(partition by b order by c) as rn from extend_infer_t3 where a>5 and c>3)t
where a>5 and c>3 and rn<3 order by 1,2,3;"""
- qt_pull_up_generate """select a,b, age from (select * from extend_infer_t3
lateral view
- EXPLODE(ARRAY(30,60)) t1 as age where a<10 ) t group by grouping sets
((age),(a,b)) having a <10 order by 1,2,3"""
+// qt_pull_up_generate """select a,b, age from (select * from
extend_infer_t3 lateral view
+// EXPLODE(ARRAY(30,60)) t1 as age where a<10 ) t group by grouping sets
((age),(a,b)) having a <10 order by 1,2,3"""
qt_pull_up_from_inner_join """select a,b from (select t1.a,t2.b from
extend_infer_t3 t1 inner join extend_infer_t4 t2 on t1.a=t2.a where t1.a<10
limit 10) t where a<10 order by 1,2"""
qt_pull_up_from_left_join """select a,b from (select t2.a,t2.b from
extend_infer_t3 t1 left join extend_infer_t4 t2 on t1.a=t2.a and t2.a<10 limit
10) t where a<10 order by 1,2"""
@@ -377,4 +377,39 @@ suite("extend_infer_equal_predicate") {
qt_pull_up_from_intersect """select a from(select a from (select t1.a from
extend_infer_t3 t1 where t1.a<10 intersect select t2.a from extend_infer_t4 t2
where t2.a<10 ) tt
limit 10) t where a<10 order by 1 ;"""
qt_pull_up_from_agg """select a from (select a from extend_infer_t3 t1
where a<10 group by a limit 10) t where a<10 order by 1"""
+
+ def explain_and_result = { tag, sql ->
+ "qt_${tag}_shape" "explain shape plan ${sql}"
+ "order_qt_${tag}_result" "${sql}"
+ }
+
+ // test left join right table predicate pull up
+ explain_and_result 'qt_leftjoin_right_pull_up_shape', '''
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left join extend_infer_t5 t3 on t2.a= t3.a where t1.a=1;
+ '''
+ // test multi left join right table predicate pull up
+ explain_and_result "qt_multi_leftjoin_right_pull_up_shape", """
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left join extend_infer_t5 t3 on t2.a= t3.a left join extend_infer_t5
t4 on t4.a=t3.a left join extend_infer_t5 t5 on t2.a=t5.a where t1.a=1;
+ """
+ explain_and_result "qt_leftjoin_right_pull_up_in_shape", """
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left join extend_infer_t5 t3 on t2.a= t3.a where t1.a in (1,2);
+ """
+ // is null may be can be inferred but we do not infer it now
+ explain_and_result "qt_leftjoin_right_pull_up_is_null_shape", """
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left join extend_infer_t5 t3 on t2.a= t3.a where t1.a is null;
+ """
+ // is not null may be need not be innfered
+ explain_and_result "qt_leftjoin_right_pull_up_is_not_null_shape", """
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left join extend_infer_t5 t3 on t2.a= t3.a where t1.a is not null;
+ """
+
+ explain_and_result 'qt_left_join_inner', '''
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a inner join extend_infer_t5 t3 on t2.a= t3.a where t1.a=1;
+ '''
+ explain_and_result 'qt_left_join_semi', '''
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left semi join extend_infer_t5 t3 on t2.a= t3.a where t1.a=1;
+ '''
+ explain_and_result 'qt_left_join_anti', '''
+ select * from extend_infer_t3 t1 left join extend_infer_t4 t2 on
t1.a=t2.a left anti join extend_infer_t5 t3 on t2.a= t3.a where t1.a=1;
+ '''
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]