You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by hu...@apache.org on 2022/07/29 13:05:24 UTC
[doris] branch master updated: [feature](nereids) add scalar subquery expression (#11332)
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 <32...@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-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org