This is an automated email from the ASF dual-hosted git repository. huajianlan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new e7fae413dd [feature](nereids) add scalar subquery expression (#11332) e7fae413dd is described below commit e7fae413ddd3547020fd2999c13d61a3c8eb2070 Author: zhengshiJ <32082872+zhengs...@users.noreply.github.com> AuthorDate: Fri Jul 29 21:05:19 2022 +0800 [feature](nereids) add scalar subquery expression (#11332) scalar subquery: A subquery that will return only one row and one column. A limit has been added, where a = subquery returns a result of 1 row and 1 column. Here, the first limit is to return 1 column. TODO: the subsequent return will limit the return to 1 row --- .../doris/nereids/parser/LogicalPlanBuilder.java | 7 ++-- .../doris/nereids/trees/expressions/Exists.java | 29 +------------ .../nereids/trees/expressions/InSubquery.java | 18 ++++----- .../expressions/{Exists.java => ListQuery.java} | 47 +++++----------------- .../{Exists.java => ScalarSubquery.java} | 42 ++++--------------- .../nereids/trees/expressions/SubqueryExpr.java | 6 +-- .../visitor/DefaultSubExprRewriter.java | 15 ++++++- .../expressions/visitor/ExpressionVisitor.java | 10 +++++ .../nereids/trees/expressions/SubqueryTest.java | 20 +++++++-- 9 files changed, 75 insertions(+), 119 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index b16f1a6c0f..d20cb728e7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -89,6 +89,7 @@ import org.apache.doris.nereids.trees.expressions.IntervalLiteral; import org.apache.doris.nereids.trees.expressions.LessThan; import org.apache.doris.nereids.trees.expressions.LessThanEqual; import org.apache.doris.nereids.trees.expressions.Like; +import org.apache.doris.nereids.trees.expressions.ListQuery; import org.apache.doris.nereids.trees.expressions.Literal; import org.apache.doris.nereids.trees.expressions.Mod; import org.apache.doris.nereids.trees.expressions.Multiply; @@ -98,8 +99,8 @@ import org.apache.doris.nereids.trees.expressions.NullLiteral; import org.apache.doris.nereids.trees.expressions.NullSafeEqual; import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Regexp; +import org.apache.doris.nereids.trees.expressions.ScalarSubquery; import org.apache.doris.nereids.trees.expressions.StringLiteral; -import org.apache.doris.nereids.trees.expressions.SubqueryExpr; import org.apache.doris.nereids.trees.expressions.Subtract; import org.apache.doris.nereids.trees.expressions.TimestampArithmetic; import org.apache.doris.nereids.trees.expressions.WhenClause; @@ -804,7 +805,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { } else { outExpression = new InSubquery( valueExpression, - typedVisit(ctx.query()) + new ListQuery(typedVisit(ctx.query())) ); } break; @@ -831,7 +832,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { @Override public Expression visitSubqueryExpression(SubqueryExpressionContext subqueryExprCtx) { - return ParserUtils.withOrigin(subqueryExprCtx, () -> new SubqueryExpr(typedVisit(subqueryExprCtx.query()))); + return ParserUtils.withOrigin(subqueryExprCtx, () -> new ScalarSubquery(typedVisit(subqueryExprCtx.query()))); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java index 1371e27054..68b7ef3429 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java @@ -23,15 +23,12 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; -import com.google.common.base.Preconditions; - -import java.util.List; import java.util.Objects; /** * Exists subquery expression. */ -public class Exists extends SubqueryExpr { +public class Exists extends SubqueryExpr implements LeafExpression { public Exists(LogicalPlan subquery) { super(Objects.requireNonNull(subquery, "subquery can not be null")); @@ -55,28 +52,4 @@ public class Exists extends SubqueryExpr { public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { return visitor.visitExistsSubquery(this, context); } - - @Override - public Expression withChildren(List<Expression> children) { - Preconditions.checkArgument(children.size() == 1); - Preconditions.checkArgument(children.get(0) instanceof SubqueryExpr); - return new Exists(((SubqueryExpr) children.get(0)).getQueryPlan()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Exists exists = (Exists) o; - return Objects.equals(this.queryPlan, exists.getQueryPlan()); - } - - @Override - public int hashCode() { - return Objects.hash(this.queryPlan); - } } 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 697fec564e..e020e22a4c 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 @@ -19,8 +19,6 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.exceptions.UnboundException; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; -import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; -import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; import com.google.common.base.Preconditions; @@ -33,15 +31,17 @@ import java.util.Objects; */ public class InSubquery extends SubqueryExpr implements BinaryExpression { private Expression compareExpr; + private ListQuery listQuery; - public InSubquery(Expression compareExpression, LogicalPlan subquery) { - super(Objects.requireNonNull(subquery, "subquery can not be null")); + public InSubquery(Expression compareExpression, ListQuery listQuery) { + super(Objects.requireNonNull(listQuery.getQueryPlan(), "subquery can not be null")); this.compareExpr = compareExpression; + this.listQuery = listQuery; } @Override public DataType getDataType() throws UnboundException { - return BooleanType.INSTANCE; + return listQuery.getDataType(); } @Override @@ -71,8 +71,8 @@ public class InSubquery extends SubqueryExpr implements BinaryExpression { public Expression withChildren(List<Expression> children) { Preconditions.checkArgument(children.size() == 2); Preconditions.checkArgument(children.get(0) instanceof Expression); - Preconditions.checkArgument(children.get(1) instanceof SubqueryExpr); - return new InSubquery(children.get(0), ((SubqueryExpr) children.get(1)).getQueryPlan()); + Preconditions.checkArgument(children.get(1) instanceof ListQuery); + return new InSubquery(children.get(0), (ListQuery) children.get(1)); } @Override @@ -85,11 +85,11 @@ public class InSubquery extends SubqueryExpr implements BinaryExpression { } InSubquery inSubquery = (InSubquery) o; return Objects.equals(this.compareExpr, inSubquery.getCompareExpr()) - && Objects.equals(this.queryPlan, inSubquery.getQueryPlan()); + && checkEquals(this.queryPlan, inSubquery.queryPlan); } @Override public int hashCode() { - return Objects.hash(this.compareExpr, this.queryPlan); + return Objects.hash(this.compareExpr, this.listQuery); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java similarity index 56% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java index 1371e27054..3fb3224183 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java @@ -20,63 +20,38 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.exceptions.UnboundException; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; -import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; -import com.google.common.base.Preconditions; - -import java.util.List; import java.util.Objects; /** - * Exists subquery expression. + * Encapsulate LogicalPlan as Expression. + * just for subquery. */ -public class Exists extends SubqueryExpr { - - public Exists(LogicalPlan subquery) { +public class ListQuery extends SubqueryExpr implements LeafExpression { + public ListQuery(LogicalPlan subquery) { super(Objects.requireNonNull(subquery, "subquery can not be null")); } @Override public DataType getDataType() throws UnboundException { - return BooleanType.INSTANCE; + // TODO: + // For multiple lines, struct type is returned, in the form of splicing, + // but it seems that struct type is not currently supported + throw new UnboundException("not support"); } @Override public String toSql() { - return "EXISTS (SUBQUERY) " + super.toSql(); + return " (LISTQUERY) " + super.toSql(); } @Override public String toString() { - return "EXISTS (SUBQUERY) " + super.toString(); + return " (LISTQUERY) " + super.toString(); } public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { - return visitor.visitExistsSubquery(this, context); - } - - @Override - public Expression withChildren(List<Expression> children) { - Preconditions.checkArgument(children.size() == 1); - Preconditions.checkArgument(children.get(0) instanceof SubqueryExpr); - return new Exists(((SubqueryExpr) children.get(0)).getQueryPlan()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Exists exists = (Exists) o; - return Objects.equals(this.queryPlan, exists.getQueryPlan()); - } - - @Override - public int hashCode() { - return Objects.hash(this.queryPlan); + return visitor.visitListQuery(this, context); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ScalarSubquery.java similarity index 58% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ScalarSubquery.java index 1371e27054..32285bac38 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ScalarSubquery.java @@ -20,63 +20,37 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.exceptions.UnboundException; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; -import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; import com.google.common.base.Preconditions; -import java.util.List; import java.util.Objects; /** - * Exists subquery expression. + * A subquery that will return only one row and one column. */ -public class Exists extends SubqueryExpr { - - public Exists(LogicalPlan subquery) { +public class ScalarSubquery extends SubqueryExpr implements LeafExpression { + public ScalarSubquery(LogicalPlan subquery) { super(Objects.requireNonNull(subquery, "subquery can not be null")); } @Override public DataType getDataType() throws UnboundException { - return BooleanType.INSTANCE; + Preconditions.checkArgument(queryPlan.getOutput().size() == 1); + return queryPlan.getOutput().get(0).getDataType(); } @Override public String toSql() { - return "EXISTS (SUBQUERY) " + super.toSql(); + return " (SCALARSUBQUERY) " + super.toSql(); } @Override public String toString() { - return "EXISTS (SUBQUERY) " + super.toString(); + return " (SCALARSUBQUERY) " + super.toString(); } public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { - return visitor.visitExistsSubquery(this, context); - } - - @Override - public Expression withChildren(List<Expression> children) { - Preconditions.checkArgument(children.size() == 1); - Preconditions.checkArgument(children.get(0) instanceof SubqueryExpr); - return new Exists(((SubqueryExpr) children.get(0)).getQueryPlan()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Exists exists = (Exists) o; - return Objects.equals(this.queryPlan, exists.getQueryPlan()); - } - - @Override - public int hashCode() { - return Objects.hash(this.queryPlan); + return visitor.visitScalarSubquery(this, context); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java index f987a1a2bf..063c2b489f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java @@ -39,10 +39,6 @@ public class SubqueryExpr extends Expression { @Override public DataType getDataType() throws UnboundException { - // TODO: - // Returns the data type of the row on a single line - // For multiple lines, struct type is returned, in the form of splicing, - // but it seems that struct type is not currently supported throw new UnboundException("not support"); } @@ -95,7 +91,7 @@ public class SubqueryExpr extends Expression { * @param o compared query. * @return equal ? true : false; */ - private boolean checkEquals(Object i, Object o) { + protected boolean checkEquals(Object i, Object o) { if (!(i instanceof LogicalPlan) || !(o instanceof LogicalPlan)) { return false; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/DefaultSubExprRewriter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/DefaultSubExprRewriter.java index 0f5c706662..c00088803d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/DefaultSubExprRewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/DefaultSubExprRewriter.java @@ -18,9 +18,12 @@ package org.apache.doris.nereids.trees.expressions.visitor; import org.apache.doris.nereids.analyzer.NereidsAnalyzer; +import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.rules.analysis.Scope; 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.ScalarSubquery; import org.apache.doris.nereids.trees.expressions.SubqueryExpr; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.qe.ConnectContext; @@ -44,7 +47,17 @@ public class DefaultSubExprRewriter<C> extends DefaultExpressionRewriter<C> { @Override public Expression visitInSubquery(InSubquery expr, C context) { - return new InSubquery(expr.getCompareExpr(), analyzeSubquery(expr)); + return new InSubquery(expr.getCompareExpr(), new ListQuery(analyzeSubquery(expr))); + } + + @Override + public Expression visitScalarSubquery(ScalarSubquery scalar, C context) { + LogicalPlan analyzed = analyzeSubquery(scalar); + if (analyzed.getOutput().size() != 1) { + throw new AnalysisException("Multiple columns returned by subquery are not yet supported. Found " + + analyzed.getOutput().size()); + } + return new ScalarSubquery(analyzed); } private LogicalPlan analyzeSubquery(SubqueryExpr expr) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java index bb1e3d5f05..e39d215a8c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java @@ -45,6 +45,7 @@ import org.apache.doris.nereids.trees.expressions.IntegerLiteral; import org.apache.doris.nereids.trees.expressions.LessThan; import org.apache.doris.nereids.trees.expressions.LessThanEqual; import org.apache.doris.nereids.trees.expressions.Like; +import org.apache.doris.nereids.trees.expressions.ListQuery; import org.apache.doris.nereids.trees.expressions.Literal; import org.apache.doris.nereids.trees.expressions.Mod; import org.apache.doris.nereids.trees.expressions.Multiply; @@ -54,6 +55,7 @@ import org.apache.doris.nereids.trees.expressions.NullLiteral; import org.apache.doris.nereids.trees.expressions.NullSafeEqual; import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Regexp; +import org.apache.doris.nereids.trees.expressions.ScalarSubquery; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.StringLiteral; @@ -240,6 +242,14 @@ public abstract class ExpressionVisitor<R, C> { return visit(arithmetic, context); } + public R visitScalarSubquery(ScalarSubquery scalar, C context) { + return visitSubqueryExpr(scalar, context); + } + + public R visitListQuery(ListQuery listQuery, C context) { + return visitSubqueryExpr(listQuery, context); + } + /* ******************************************************************************************** * Unbound expressions * ********************************************************************************************/ diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/SubqueryTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/SubqueryTest.java index 663aea728e..e731c26776 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/SubqueryTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/SubqueryTest.java @@ -83,16 +83,30 @@ public class SubqueryTest extends AnalyzeCheckTestBase { @Test public void scalarTest() { - String sql = "select * from t0 where t0.id = " + // min will be rewritten as as, it needs to be bound + /*String sql = "select * from t0 where t0.id = " + "(select min(t1.id) from t1 where t0.k1 = t1.k1)"; - checkAnalyze(sql); + checkAnalyze(sql);*/ + + // Require that the return value in the where subquery must have only 1 column. + String sql1 = "select * from t0 where t0.id = " + + "(select t1.k1, t1.id from t1 where t0.k1 = t1.k1)"; + assert sql1 != null; + + String sql2 = "select * from t0 where t0.id = " + + "(select t1.k1 from t1 where t0.k1 = t1.k1)"; + checkAnalyze(sql2); + + String sql3 = "select * from t0 where t0.id = " + + "(select * from t1 where t0.k1 = t1.k1)"; + assert sql3 != null; } @Test public void inScalarTest() { String sql = "select * from t0 where t0.id in " + "(select * from t1 where t1.k1 = " - + "(select * from t2 where t0.id = t2.id));"; + + "(select t2.id from t2 where t0.id = t2.id));"; checkAnalyze(sql); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org