From 445484270bec7ac91fd9347b652695d90affcca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E5=81=A5?= Date: Tue, 21 Nov 2023 18:54:58 +0800 Subject: [PATCH] [fix](Nereids): fill miss slot in having subquery (#27177) fill miss slot in having subquery. such as ``` select * from t group by k having max(k) in (select k from t2) ``` the max(k) should be push down aggregate --- .../rules/analysis/SubqueryToApply.java | 19 ++++++++++++++----- .../nereids/trees/expressions/InSubquery.java | 6 ++++++ .../nereids_p0/subquery/test_subquery.groovy | 7 +++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java index 2852db1108..c236e1b325 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java @@ -21,11 +21,13 @@ import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.StatementContext; 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.BinaryOperator; import org.apache.doris.nereids.trees.expressions.Exists; import org.apache.doris.nereids.trees.expressions.Expression; 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.Or; @@ -73,7 +75,7 @@ public class SubqueryToApply implements AnalysisRuleFactory { LogicalFilter filter = ctx.root; ImmutableList> subqueryExprsList = filter.getConjuncts().stream() - .>map(e -> e.collect(SubqueryExpr.class::isInstance)) + .>map(e -> e.collect(SubqueryToApply::canConvertToSupply)) .collect(ImmutableList.toImmutableList()); if (subqueryExprsList.stream() .flatMap(Collection::stream).noneMatch(SubqueryExpr.class::isInstance)) { @@ -122,7 +124,7 @@ public class SubqueryToApply implements AnalysisRuleFactory { RuleType.PROJECT_SUBQUERY_TO_APPLY.build(logicalProject().thenApply(ctx -> { LogicalProject project = ctx.root; ImmutableList> subqueryExprsList = project.getProjects().stream() - .>map(e -> e.collect(SubqueryExpr.class::isInstance)) + .>map(e -> e.collect(SubqueryToApply::canConvertToSupply)) .collect(ImmutableList.toImmutableList()); if (subqueryExprsList.stream().flatMap(Collection::stream).count() == 0) { return project; @@ -191,7 +193,7 @@ public class SubqueryToApply implements AnalysisRuleFactory { } ImmutableList> subqueryExprsList = subqueryConjuncts.stream() - .>map(e -> e.collect(SubqueryExpr.class::isInstance)) + .>map(e -> e.collect(SubqueryToApply::canConvertToSupply)) .collect(ImmutableList.toImmutableList()); ImmutableList.Builder newConjuncts = new ImmutableList.Builder<>(); LogicalPlan applyPlan; @@ -235,10 +237,17 @@ public class SubqueryToApply implements AnalysisRuleFactory { ); } + private static boolean canConvertToSupply(TreeNode expression) { + // The subquery except ListQuery can be converted to Supply + return expression instanceof SubqueryExpr && !(expression instanceof ListQuery); + } + private static boolean isValidSubqueryConjunct(Expression expression) { // only support 1 subquery expr in the expression // don't support expression like subquery1 or subquery2 - return expression.collectToList(SubqueryExpr.class::isInstance).size() == 1; + return expression + .collectToList(SubqueryToApply::canConvertToSupply) + .size() == 1; } private enum RelatedInfo { @@ -264,7 +273,7 @@ public class SubqueryToApply implements AnalysisRuleFactory { Set rightOutputSlots = rightChild.getOutputSet(); for (int i = 0; i < size; ++i) { Expression expression = subqueryConjuncts.get(i); - List subqueryExprs = expression.collectToList(SubqueryExpr.class::isInstance); + List subqueryExprs = expression.collectToList(SubqueryToApply::canConvertToSupply); RelatedInfo relatedInfo = RelatedInfo.UnSupported; if (subqueryExprs.size() == 1) { SubqueryExpr subqueryExpr = subqueryExprs.get(0); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java index 8f9732a2f7..e04d1b2017 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import java.util.List; import java.util.Objects; @@ -107,6 +108,11 @@ public class InSubquery extends SubqueryExpr { return new InSubquery(children.get(0), (ListQuery) children.get(1), isNot); } + @Override + public List children() { + return Lists.newArrayList(compareExpr, listQuery); + } + @Override public boolean equals(Object o) { if (!super.equals(o)) { diff --git a/regression-test/suites/nereids_p0/subquery/test_subquery.groovy b/regression-test/suites/nereids_p0/subquery/test_subquery.groovy index 7170fd20d5..dfb79c771d 100644 --- a/regression-test/suites/nereids_p0/subquery/test_subquery.groovy +++ b/regression-test/suites/nereids_p0/subquery/test_subquery.groovy @@ -52,6 +52,13 @@ suite("test_subquery") { select * from nereids_test_query_db.baseall where k1 = (select k1 from nereids_test_query_db.baseall limit 1) """ + // test uncorrelated subquery in having + sql """ + select count(*) from nereids_test_query_db.baseall + group by k0 + having min(k0) in (select k0 from nereids_test_query_db.baseall) + """ + // test uncorrelated scalar subquery with more than one return rows test { sql """