[fix](nereids)subquery unnest need handle subquery in Not expr correnctly (#28713)

This commit is contained in:
starocean999
2023-12-25 11:23:00 +08:00
committed by GitHub
parent 6085a61f1e
commit 99755920e2
3 changed files with 127 additions and 5 deletions

View File

@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.And;
import org.apache.doris.nereids.trees.expressions.BinaryOperator;
import org.apache.doris.nereids.trees.expressions.Exists;
import org.apache.doris.nereids.trees.expressions.Expression;
@ -30,6 +31,7 @@ import org.apache.doris.nereids.trees.expressions.InSubquery;
import org.apache.doris.nereids.trees.expressions.ListQuery;
import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Not;
import org.apache.doris.nereids.trees.expressions.Or;
import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
import org.apache.doris.nereids.trees.expressions.Slot;
@ -38,7 +40,6 @@ import org.apache.doris.nereids.trees.expressions.SubqueryExpr;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalApply;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
@ -73,7 +74,8 @@ public class SubqueryToApply implements AnalysisRuleFactory {
RuleType.FILTER_SUBQUERY_TO_APPLY.build(
logicalFilter().thenApply(ctx -> {
LogicalFilter<Plan> filter = ctx.root;
boolean shouldOutputMarkJoinSlot = filter.getConjuncts().stream()
.anyMatch(expr -> shouldOutputMarkJoinSlot(expr, SearchState.SearchNot));
ImmutableList<Set<SubqueryExpr>> subqueryExprsList = filter.getConjuncts().stream()
.<Set<SubqueryExpr>>map(e -> e.collect(SubqueryToApply::canConvertToSupply))
.collect(ImmutableList.toImmutableList());
@ -98,7 +100,7 @@ public class SubqueryToApply implements AnalysisRuleFactory {
// first step: Replace the subquery of predicate in LogicalFilter
// second step: Replace subquery with LogicalApply
ReplaceSubquery replaceSubquery = new ReplaceSubquery(
ctx.statementContext, false);
ctx.statementContext, shouldOutputMarkJoinSlot);
SubqueryContext context = new SubqueryContext(subqueryExprs);
Expression conjunct = replaceSubquery.replace(oldConjuncts.get(i), context);
@ -343,7 +345,7 @@ public class SubqueryToApply implements AnalysisRuleFactory {
&& hasTopLevelAggWithoutGroupBy(exists.getQueryPlan());
}
private boolean hasTopLevelAggWithoutGroupBy(Plan plan) {
private static boolean hasTopLevelAggWithoutGroupBy(Plan plan) {
if (plan instanceof LogicalAggregate) {
return ((LogicalAggregate) plan).getGroupByExpressions().isEmpty();
} else if (plan instanceof LogicalProject || plan instanceof LogicalSort) {
@ -427,7 +429,7 @@ public class SubqueryToApply implements AnalysisRuleFactory {
// it will always consider the returned result to be true
boolean needCreateMarkJoinSlot = isMarkJoin || shouldOutputMarkJoinSlot;
MarkJoinSlotReference markJoinSlotReference = null;
if (exists.getQueryPlan().anyMatch(Aggregate.class::isInstance) && needCreateMarkJoinSlot) {
if (hasTopLevelAggWithoutGroupBy(exists.getQueryPlan()) && needCreateMarkJoinSlot) {
markJoinSlotReference =
new MarkJoinSlotReference(statementContext.generateColumnName(), true);
} else if (needCreateMarkJoinSlot) {
@ -505,4 +507,27 @@ public class SubqueryToApply implements AnalysisRuleFactory {
}
private enum SearchState {
SearchNot,
SearchAnd,
SearchExistsOrInSubquery
}
private boolean shouldOutputMarkJoinSlot(Expression expr, SearchState searchState) {
if (searchState == SearchState.SearchNot && expr instanceof Not) {
if (shouldOutputMarkJoinSlot(((Not) expr).child(), SearchState.SearchAnd)) {
return true;
}
} else if (searchState == SearchState.SearchAnd && expr instanceof And) {
for (Expression child : expr.children()) {
if (shouldOutputMarkJoinSlot(child, SearchState.SearchExistsOrInSubquery)) {
return true;
}
}
} else if (searchState == SearchState.SearchExistsOrInSubquery
&& (expr instanceof InSubquery || expr instanceof Exists)) {
return true;
}
return false;
}
}