This is an automated email from the ASF dual-hosted git repository. caogaofei pushed a commit to branch beyyes/debug-table in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit c91c3984a1391b0fa5b65029c071e3c4f589a922 Author: Beyyes <[email protected]> AuthorDate: Sat Apr 27 10:27:44 2024 +0800 add bewteen and, is null, is not null, substring, like, round --- .../relational/ColumnTransformerBuilder.java | 33 --- .../plan/relational/planner/PlanBuilder.java | 2 +- .../plan/relational/planner/QueryPlanner.java | 8 +- .../relational/planner/ir/ExpressionRewriter.java | 14 +- .../planner/ir/ExpressionTranslateVisitor.java | 94 +++++--- .../planner/ir/ExpressionTreeRewriter.java | 84 +------ .../ExtractCommonPredicatesExpressionRewriter.java | 22 +- .../ir/GlobalTimePredicateExtractVisitor.java | 247 +++++++++++++++++++++ .../plan/relational/planner/ir/IrVisitor.java | 25 --- .../planner/ir/NormalizeOrExpressionRewriter.java | 10 +- .../relational/planner/ir/RewritingVisitor.java | 221 ++++++++++++++++++ 11 files changed, 552 insertions(+), 208 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java index 756be2226f3..2d4ce5ac0e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java @@ -180,39 +180,6 @@ public class ColumnTransformerBuilder return res; } - private ColumnTransformer getArithmeticBinaryTransformer( - ArithmeticBinaryExpression node, Context context) { - if (context.hasSeen.containsKey(node)) { - IdentityColumnTransformer identity = - new IdentityColumnTransformer( - DOUBLE, context.originSize + context.commonTransformerList.size()); - ColumnTransformer columnTransformer = context.hasSeen.get(node); - columnTransformer.addReferenceCount(); - context.commonTransformerList.add(columnTransformer); - context.leafList.add(identity); - context.inputDataTypes.add(TSDataType.DOUBLE); - return identity; - } else { - ColumnTransformer left = process(node.getLeft(), context); - ColumnTransformer right = process(node.getRight(), context); - switch (node.getOperator()) { - case ADD: - return new ArithmeticAdditionColumnTransformer(DOUBLE, left, right); - case SUBTRACT: - return new ArithmeticSubtractionColumnTransformer(DOUBLE, left, right); - case MULTIPLY: - return new ArithmeticMultiplicationColumnTransformer(DOUBLE, left, right); - case DIVIDE: - return new ArithmeticDivisionColumnTransformer(DOUBLE, left, right); - case MODULUS: - return new ArithmeticModuloColumnTransformer(DOUBLE, left, right); - default: - throw new UnsupportedOperationException( - String.format(UNSUPPORTED_EXPRESSION, node.getOperator())); - } - } - } - @Override protected ColumnTransformer visitArithmeticUnary( ArithmeticUnaryExpression node, Context context) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java index 38af83ec7f8..4e0d3982949 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java @@ -82,7 +82,7 @@ public class PlanBuilder { } private Expression translate(Expression expression) { - return new ExpressionTranslateVisitor().process(expression, this); + return ExpressionTranslateVisitor.translateToSymbolReference(expression, this); } public Optional<Symbol> getSymbolForColumn(Expression expression) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java index 5f1f193e2e6..a99e0f473e1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java @@ -19,6 +19,7 @@ import org.apache.iotdb.db.queryengine.common.SessionInfo; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis; import org.apache.iotdb.db.queryengine.plan.relational.analyzer.NodeRef; +import org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionTranslateVisitor; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.LimitNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode; @@ -50,7 +51,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Objects.requireNonNull; import static org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingTranslator.sortItemToSortOrder; import static org.apache.iotdb.db.queryengine.plan.relational.planner.PlanBuilder.newPlanBuilder; -import static org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.GlobalTimePredicateExtractVisitor.extractGlobalTimeFilter; public class QueryPlanner { private final Analysis analysis; @@ -244,8 +245,9 @@ public class QueryPlanner { return planBuilder; } - Pair<Expression, Boolean> resultPair = extractGlobalTimePredicate(predicate, true, true); - Expression globalTimePredicate = resultPair.left; + Pair<Expression, Boolean> resultPair = extractGlobalTimeFilter(predicate); + Expression globalTimePredicate = + ExpressionTranslateVisitor.translateToSymbolReference(resultPair.left, planBuilder); analysis.setGlobalTableModelTimePredicate(globalTimePredicate); boolean hasValueFilter = resultPair.right; if (!hasValueFilter) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionRewriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionRewriter.java index e0d72f48928..13b8daf01da 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionRewriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionRewriter.java @@ -37,9 +37,13 @@ import org.apache.iotdb.db.relational.sql.tree.SimpleCaseExpression; import org.apache.iotdb.db.relational.sql.tree.SymbolReference; public class ExpressionRewriter<C> { + protected Expression rewriteExpression( Expression node, C context, ExpressionTreeRewriter<C> treeRewriter) { return null; + // throw new IllegalStateException( + // String.format("%s is not supported in ExpressionRewriter yet", + // node.getClass().getName())); } public Expression rewriteRow(Row node, C context, ExpressionTreeRewriter<C> treeRewriter) { @@ -106,11 +110,6 @@ public class ExpressionRewriter<C> { return rewriteExpression(node, context, treeRewriter); } - // public Expression rewriteLambdaExpression(LambdaExpression node, C context, - // ExpressionTreeRewriter<C> treeRewriter) { - // return rewriteExpression(node, context, treeRewriter); - // } - // public Expression rewriteBindExpression(BindExpression node, C context, // ExpressionTreeRewriter<C> treeRewriter) { // return rewriteExpression(node, context, treeRewriter); @@ -126,11 +125,6 @@ public class ExpressionRewriter<C> { // return rewriteExpression(node, context, treeRewriter); // } - // public Expression rewriteSubscriptExpression(SubscriptExpression node, C context, - // ExpressionTreeRewriter<C> treeRewriter) { - // return rewriteExpression(node, context, treeRewriter); - // } - public Expression rewriteCast(Cast node, C context, ExpressionTreeRewriter<C> treeRewriter) { return rewriteExpression(node, context, treeRewriter); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTranslateVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTranslateVisitor.java index 400184f91b0..c7a05609bde 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTranslateVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTranslateVisitor.java @@ -16,14 +16,12 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.ir; import org.apache.iotdb.db.queryengine.plan.relational.planner.PlanBuilder; import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import org.apache.iotdb.db.relational.sql.tree.ArithmeticBinaryExpression; -import org.apache.iotdb.db.relational.sql.tree.AstVisitor; -import org.apache.iotdb.db.relational.sql.tree.BetweenPredicate; import org.apache.iotdb.db.relational.sql.tree.ComparisonExpression; import org.apache.iotdb.db.relational.sql.tree.Expression; +import org.apache.iotdb.db.relational.sql.tree.FunctionCall; import org.apache.iotdb.db.relational.sql.tree.Identifier; import org.apache.iotdb.db.relational.sql.tree.IfExpression; import org.apache.iotdb.db.relational.sql.tree.InPredicate; -import org.apache.iotdb.db.relational.sql.tree.IsNotNullPredicate; import org.apache.iotdb.db.relational.sql.tree.IsNullPredicate; import org.apache.iotdb.db.relational.sql.tree.LikePredicate; import org.apache.iotdb.db.relational.sql.tree.Literal; @@ -34,39 +32,42 @@ import org.apache.iotdb.db.relational.sql.tree.SearchedCaseExpression; import org.apache.iotdb.db.relational.sql.tree.SimpleCaseExpression; import org.apache.iotdb.db.relational.sql.tree.SymbolReference; +import java.util.List; +import java.util.stream.Collectors; + import static com.google.common.collect.ImmutableList.toImmutableList; /** Change Identifier to SymbolReference */ -public class ExpressionTranslateVisitor extends AstVisitor<Expression, PlanBuilder> { +public class ExpressionTranslateVisitor extends RewritingVisitor<PlanBuilder> { - @Override - protected Expression visitSymbolReference(SymbolReference node, PlanBuilder context) { - return new SymbolReference(context.getSymbolForColumn(node).get().getName()); - } + private ExpressionTranslateVisitor() {} - @Override - protected Expression visitIdentifier(Identifier node, PlanBuilder context) { - return context.getSymbolForColumn(node).map(Symbol::toSymbolReference).get(); + private static final String NOT_SUPPORTED = "%s is not supported expression translate yet."; + + public static Expression translateToSymbolReference( + Expression expression, PlanBuilder planBuilder) { + return new ExpressionTranslateVisitor().process(expression, planBuilder); } @Override - protected Expression visitInPredicate(InPredicate node, PlanBuilder context) { - return null; + protected Expression visitExpression(Expression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); } @Override - protected Expression visitIsNullPredicate(IsNullPredicate node, PlanBuilder context) { - return null; + protected Expression visitSymbolReference(SymbolReference node, PlanBuilder context) { + return new SymbolReference(context.getSymbolForColumn(node).get().getName()); } @Override - protected Expression visitIsNotNullPredicate(IsNotNullPredicate node, PlanBuilder context) { - return null; + protected Expression visitIdentifier(Identifier node, PlanBuilder context) { + return context.getSymbolForColumn(node).map(Symbol::toSymbolReference).get(); } @Override - protected Expression visitLikePredicate(LikePredicate node, PlanBuilder context) { - return null; + protected Expression visitArithmeticBinary(ArithmeticBinaryExpression node, PlanBuilder context) { + return new ArithmeticBinaryExpression( + node.getOperator(), process(node.getLeft(), context), process(node.getRight(), context)); } @Override @@ -77,8 +78,8 @@ public class ExpressionTranslateVisitor extends AstVisitor<Expression, PlanBuild } @Override - protected Expression visitNotExpression(NotExpression node, PlanBuilder context) { - return null; + protected Expression visitLiteral(Literal node, PlanBuilder context) { + return node; } @Override @@ -89,39 +90,58 @@ public class ExpressionTranslateVisitor extends AstVisitor<Expression, PlanBuild } @Override - protected Expression visitSimpleCaseExpression(SimpleCaseExpression node, PlanBuilder context) { - return null; + protected Expression visitFunctionCall(FunctionCall node, PlanBuilder context) { + List<Expression> newArguments = + node.getArguments().stream() + .map(argument -> process(argument, context)) + .collect(Collectors.toList()); + return new FunctionCall(node.getName(), newArguments); } @Override - protected Expression visitSearchedCaseExpression( - SearchedCaseExpression node, PlanBuilder context) { - return null; + protected Expression visitIsNullPredicate(IsNullPredicate node, PlanBuilder context) { + return new IsNullPredicate(process(node.getValue(), context)); } @Override - protected Expression visitIfExpression(IfExpression node, PlanBuilder context) { - return null; + protected Expression visitInPredicate(InPredicate node, PlanBuilder context) { + return new InPredicate( + process(node.getValue(), context), process(node.getValueList(), context)); } @Override - protected Expression visitNullIfExpression(NullIfExpression node, PlanBuilder context) { - return null; + protected Expression visitLikePredicate(LikePredicate node, PlanBuilder context) { + return new LikePredicate( + process(node.getValue(), context), + process(node.getPattern(), context), + process(node.getPattern(), context)); } + // ============================ not implemented ======================================= + @Override - protected Expression visitBetweenPredicate(BetweenPredicate node, PlanBuilder context) { - return null; + protected Expression visitNotExpression(NotExpression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); } @Override - protected Expression visitArithmeticBinary(ArithmeticBinaryExpression node, PlanBuilder context) { - return new ArithmeticBinaryExpression( - node.getOperator(), process(node.getLeft(), context), process(node.getRight(), context)); + protected Expression visitSimpleCaseExpression(SimpleCaseExpression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); } @Override - protected Expression visitLiteral(Literal node, PlanBuilder context) { - return node; + protected Expression visitSearchedCaseExpression( + SearchedCaseExpression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); + } + + @Override + protected Expression visitIfExpression(IfExpression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); + } + + @Override + protected Expression visitNullIfExpression(NullIfExpression node, PlanBuilder context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass().getName())); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTreeRewriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTreeRewriter.java index e2367eb8602..fb9cc31cecc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTreeRewriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTreeRewriter.java @@ -49,6 +49,11 @@ public final class ExpressionTreeRewriter<C> { private final ExpressionRewriter<C> rewriter; private final IrVisitor<Expression, Context<C>> visitor; + public ExpressionTreeRewriter(ExpressionRewriter<C> rewriter) { + this.rewriter = rewriter; + this.visitor = new RewritingVisitor(); + } + public static <T extends Expression> T rewriteWith(ExpressionRewriter<Void> rewriter, T node) { return new ExpressionTreeRewriter<>(rewriter).rewrite(node, null); } @@ -58,11 +63,6 @@ public final class ExpressionTreeRewriter<C> { return new ExpressionTreeRewriter<>(rewriter).rewrite(node, context); } - public ExpressionTreeRewriter(ExpressionRewriter<C> rewriter) { - this.rewriter = rewriter; - this.visitor = new RewritingVisitor(); - } - private List<Expression> rewrite(List<Expression> items, Context<C> context) { ImmutableList.Builder<Expression> builder = ImmutableList.builder(); for (Expression expression : items) { @@ -86,6 +86,7 @@ public final class ExpressionTreeRewriter<C> { } private class RewritingVisitor extends IrVisitor<Expression, Context<C>> { + @Override protected Expression visitExpression(Expression node, Context<C> context) { // RewritingVisitor must have explicit support for each expression type, with a dedicated @@ -155,28 +156,6 @@ public final class ExpressionTreeRewriter<C> { return node; } - // @Override - // protected Expression visitSubscriptExpression(SubscriptExpression node, Context<C> - // context) - // { - // if (!context.isDefaultRewrite()) { - // Expression result = rewriter.rewriteSubscriptExpression(node, context.get(), - // ExpressionTreeRewriter.this); - // if (result != null) { - // return result; - // } - // } - // - // Expression base = rewrite(node.getBase(), context.get()); - // Expression index = rewrite(node.getIndex(), context.get()); - // - // if (base != node.getBase() || index != node.getIndex()) { - // return new SubscriptExpression(base, index); - // } - // - // return node; - // } - @Override public Expression visitComparisonExpression(ComparisonExpression node, Context<C> context) { if (!context.isDefaultRewrite()) { @@ -400,53 +379,6 @@ public final class ExpressionTreeRewriter<C> { return node; } - // @Override - // protected Expression visitLambdaExpression(LambdaExpression node, Context<C> context) - // { - // if (!context.isDefaultRewrite()) { - // Expression result = rewriter.rewriteLambdaExpression(node, context.get(), - // ExpressionTreeRewriter.this); - // if (result != null) { - // return result; - // } - // } - // - // List<String> arguments = node.getArguments().stream() - // .map(SymbolReference::new) - // .map(expression -> rewrite(expression, context.get())) - // .map(SymbolReference::getName) - // .collect(toImmutableList()); - // - // Expression body = rewrite(node.getBody(), context.get()); - // if (body != node.getBody()) { - // return new LambdaExpression(arguments, body); - // } - // - // return node; - // } - - // @Override - // protected Expression visitBindExpression(BindExpression node, Context<C> context) - // { - // if (!context.isDefaultRewrite()) { - // Expression result = rewriter.rewriteBindExpression(node, context.get(), - // ExpressionTreeRewriter.this); - // if (result != null) { - // return result; - // } - // } - // - // List<Expression> values = node.getValues().stream() - // .map(value -> rewrite(value, context.get())) - // .collect(toImmutableList()); - // Expression function = rewrite(node.getFunction(), context.get()); - // - // if (!sameElements(values, node.getValues()) || (function != node.getFunction())) { - // return new BindExpression(values, function); - // } - // return node; - // } - @Override public Expression visitInPredicate(InPredicate node, Context<C> context) { if (!context.isDefaultRewrite()) { @@ -544,7 +476,7 @@ public final class ExpressionTreeRewriter<C> { } } - private static <T> boolean sameElements(Optional<T> a, Optional<T> b) { + public static <T> boolean sameElements(Optional<T> a, Optional<T> b) { if (!a.isPresent() && !b.isPresent()) { return true; } @@ -556,7 +488,7 @@ public final class ExpressionTreeRewriter<C> { } @SuppressWarnings("ObjectEquality") - private static <T> boolean sameElements(Iterable<? extends T> a, Iterable<? extends T> b) { + public static <T> boolean sameElements(Iterable<? extends T> a, Iterable<? extends T> b) { if (Iterables.size(a) != Iterables.size(b)) { return false; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java index 154eff8c547..96ced66c660 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExtractCommonPredicatesExpressionRewriter.java @@ -42,34 +42,20 @@ import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator public final class ExtractCommonPredicatesExpressionRewriter { public static Expression extractCommonPredicates(Expression expression) { - return ExpressionTreeRewriter.rewriteWith(new Visitor(), expression, NodeContext.ROOT_NODE); + return new Visitor().process(expression, NodeContext.ROOT_NODE); } private ExtractCommonPredicatesExpressionRewriter() {} - private static class Visitor extends ExpressionRewriter<NodeContext> { - @Override - protected Expression rewriteExpression( - Expression node, NodeContext context, ExpressionTreeRewriter<NodeContext> treeRewriter) { - if (context.isRootNode()) { - return treeRewriter.rewrite(node, NodeContext.NOT_ROOT_NODE); - } - - return null; - } + private static class Visitor extends RewritingVisitor<NodeContext> { @Override - public Expression rewriteLogicalExpression( - LogicalExpression node, - NodeContext context, - ExpressionTreeRewriter<NodeContext> treeRewriter) { + public Expression visitLogicalExpression(LogicalExpression node, NodeContext context) { Expression expression = combinePredicates( node.getOperator(), extractPredicates(node.getOperator(), node).stream() - .map( - subExpression -> - treeRewriter.rewrite(subExpression, NodeContext.NOT_ROOT_NODE)) + .map(subExpression -> process(subExpression, NodeContext.NOT_ROOT_NODE)) .collect(toImmutableList())); if (!(expression instanceof LogicalExpression)) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/GlobalTimePredicateExtractVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/GlobalTimePredicateExtractVisitor.java new file mode 100644 index 00000000000..2d0b185f617 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/GlobalTimePredicateExtractVisitor.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.planner.ir; + +import org.apache.iotdb.db.relational.sql.tree.ArithmeticBinaryExpression; +import org.apache.iotdb.db.relational.sql.tree.BetweenPredicate; +import org.apache.iotdb.db.relational.sql.tree.ComparisonExpression; +import org.apache.iotdb.db.relational.sql.tree.Expression; +import org.apache.iotdb.db.relational.sql.tree.FunctionCall; +import org.apache.iotdb.db.relational.sql.tree.Identifier; +import org.apache.iotdb.db.relational.sql.tree.IfExpression; +import org.apache.iotdb.db.relational.sql.tree.InPredicate; +import org.apache.iotdb.db.relational.sql.tree.IsNotNullPredicate; +import org.apache.iotdb.db.relational.sql.tree.IsNullPredicate; +import org.apache.iotdb.db.relational.sql.tree.LikePredicate; +import org.apache.iotdb.db.relational.sql.tree.LogicalExpression; +import org.apache.iotdb.db.relational.sql.tree.LongLiteral; +import org.apache.iotdb.db.relational.sql.tree.NotExpression; +import org.apache.iotdb.db.relational.sql.tree.NullIfExpression; +import org.apache.iotdb.db.relational.sql.tree.SearchedCaseExpression; +import org.apache.iotdb.db.relational.sql.tree.SimpleCaseExpression; + +import org.apache.tsfile.utils.Pair; + +import java.util.Arrays; + +import static org.apache.iotdb.commons.conf.IoTDBConstant.TIME; +import static org.apache.iotdb.db.relational.sql.tree.BooleanLiteral.TRUE_LITERAL; +import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator.AND; +import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator.OR; +import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.and; +import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.or; + +public class GlobalTimePredicateExtractVisitor + extends IrVisitor<Pair<Expression, Boolean>, GlobalTimePredicateExtractVisitor.Context> { + + private static final String NOT_SUPPORTED = + "visit() not implemented for %s in GlobalTimePredicateExtract."; + + public static Pair<Expression, Boolean> extractGlobalTimeFilter(Expression predicate) { + return new GlobalTimePredicateExtractVisitor() + .process(predicate, new GlobalTimePredicateExtractVisitor.Context(true, true)); + } + + protected Pair<Expression, Boolean> visitExpression( + Pair<Expression, Boolean> node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitLogicalExpression( + LogicalExpression node, Context context) { + if (node.getOperator() == AND) { + Pair<Expression, Boolean> leftResultPair = process(node.getTerms().get(0), context); + Pair<Expression, Boolean> rightResultPair = process(node.getTerms().get(1), context); + + // rewrite predicate to avoid duplicate calculation on time filter + // If Left-child or Right-child does not contain value filter + // We can set it to true in Predicate Tree + if (context.canRewrite) { + Expression newLeftExpression = null, newRightExpression = null; + if (leftResultPair.left != null && !leftResultPair.right) { + newLeftExpression = TRUE_LITERAL; + } + if (rightResultPair.left != null && !rightResultPair.right) { + newRightExpression = TRUE_LITERAL; + } + if (newLeftExpression != null || newRightExpression != null) { + node.setTerms( + Arrays.asList( + newLeftExpression != null ? newLeftExpression : node.getTerms().get(0), + newRightExpression != null ? newRightExpression : node.getTerms().get(1))); + } + } + + if (leftResultPair.left != null && rightResultPair.left != null) { + return new Pair<>( + and(leftResultPair.left, rightResultPair.left), + leftResultPair.right || rightResultPair.right); + } else if (leftResultPair.left != null) { + return new Pair<>(leftResultPair.left, true); + } else if (rightResultPair.left != null) { + return new Pair<>(rightResultPair.left, true); + } + + return new Pair<>(null, true); + } else if (node.getOperator() == OR) { + Pair<Expression, Boolean> leftResultPair = + process(node.getTerms().get(0), new Context(false, false)); + Pair<Expression, Boolean> rightResultPair = + process(node.getTerms().get(1), new Context(false, false)); + + if (leftResultPair.left != null && rightResultPair.left != null) { + if (Boolean.TRUE.equals( + context.isFirstOr && !leftResultPair.right && !rightResultPair.right)) { + node.getTerms().set(0, TRUE_LITERAL); + node.getTerms().set(0, TRUE_LITERAL); + } + return new Pair<>( + or(leftResultPair.left, rightResultPair.left), + leftResultPair.right || rightResultPair.right); + } + return new Pair<>(null, true); + } else { + throw new IllegalStateException("Illegal state in visitLogicalExpression"); + } + } + + @Override + protected Pair<Expression, Boolean> visitComparisonExpression( + ComparisonExpression node, Context context) { + Expression leftExpression = node.getLeft(); + Expression rightExpression = node.getRight(); + if (checkIsTimeFilter(leftExpression, rightExpression) + || checkIsTimeFilter(rightExpression, leftExpression)) { + return new Pair<>(node, false); + } + return new Pair<>(null, true); + } + + @Override + protected Pair<Expression, Boolean> visitIsNullPredicate(IsNullPredicate node, Context context) { + // time filter don't support IS_NULL + return new Pair<>(null, true); + } + + @Override + protected Pair<Expression, Boolean> visitIsNotNullPredicate( + IsNotNullPredicate node, Context context) { + return new Pair<>(null, true); + } + + @Override + protected Pair<Expression, Boolean> visitFunctionCall(FunctionCall node, Context context) { + return new Pair<>(null, true); + } + + @Override + protected Pair<Expression, Boolean> visitLikePredicate(LikePredicate node, Context context) { + return new Pair<>(null, true); + } + + @Override + protected Pair<Expression, Boolean> visitBetweenPredicate( + BetweenPredicate node, Context context) { + Expression firstExpression = node.getValue(); + Expression secondExpression = node.getMin(); + Expression thirdExpression = node.getMax(); + + boolean isTimeFilter = false; + if (isTimeIdentifier(firstExpression)) { + isTimeFilter = checkBetweenConstantSatisfy(secondExpression, thirdExpression); + } else if (isTimeIdentifier(secondExpression)) { + isTimeFilter = checkBetweenConstantSatisfy(firstExpression, thirdExpression); + } else if (isTimeIdentifier(thirdExpression)) { + isTimeFilter = checkBetweenConstantSatisfy(secondExpression, firstExpression); + } + if (isTimeFilter) { + return new Pair<>(node, false); + } + return new Pair<>(null, true); + } + + // ============================ not implemented ======================================= + + @Override + protected Pair<Expression, Boolean> visitArithmeticBinary( + ArithmeticBinaryExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitInPredicate(InPredicate node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitNotExpression(NotExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitSimpleCaseExpression( + SimpleCaseExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitSearchedCaseExpression( + SearchedCaseExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitIfExpression(IfExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + @Override + protected Pair<Expression, Boolean> visitNullIfExpression( + NullIfExpression node, Context context) { + throw new IllegalStateException(String.format(NOT_SUPPORTED, node.getClass())); + } + + private static boolean isTimeIdentifier(Expression e) { + return e instanceof Identifier && TIME.equalsIgnoreCase(((Identifier) e).getValue()); + } + + private static boolean checkIsTimeFilter(Expression timeExpression, Expression valueExpression) { + return timeExpression instanceof Identifier + && ((Identifier) timeExpression).getValue().equalsIgnoreCase(TIME) + && valueExpression instanceof LongLiteral; + } + + private static boolean checkBetweenConstantSatisfy(Expression e1, Expression e2) { + return e1 instanceof LongLiteral + && e2 instanceof LongLiteral + && ((LongLiteral) e1).getParsedValue() <= ((LongLiteral) e2).getParsedValue(); + } + + public static class Context { + boolean canRewrite; + boolean isFirstOr; + + public Context(boolean canRewrite, boolean isFirstOr) { + this.canRewrite = canRewrite; + this.isFirstOr = isFirstOr; + } + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/IrVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/IrVisitor.java index 96bc02b17e0..bc7a2ff6681 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/IrVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/IrVisitor.java @@ -65,11 +65,6 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, C> { return visitExpression(node, context); } - // protected R visitConstant(Constant node, C context) - // { - // return visitExpression(node, context); - // } - protected R visitInPredicate(InPredicate node, C context) { return visitExpression(node, context); } @@ -78,11 +73,6 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, C> { return visitExpression(node, context); } - // protected R visitLambdaExpression(LambdaExpression node, C context) - // { - // return visitExpression(node, context); - // } - protected R visitSimpleCaseExpression(SimpleCaseExpression node, C context) { return visitExpression(node, context); } @@ -91,11 +81,6 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, C> { return visitExpression(node, context); } - // protected R visitArithmeticNegation(ArithmeticNegation node, C context) - // { - // return visitExpression(node, context); - // } - protected R visitNotExpression(NotExpression node, C context) { return visitExpression(node, context); } @@ -108,11 +93,6 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, C> { return visitExpression(node, context); } - // protected R visitSubscriptExpression(SubscriptExpression node, C context) - // { - // return visitExpression(node, context); - // } - protected R visitLogicalExpression(LogicalExpression node, C context) { return visitExpression(node, context); } @@ -128,9 +108,4 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, C> { protected R visitSymbolReference(SymbolReference node, C context) { return visitExpression(node, context); } - - // protected R visitBindExpression(BindExpression node, C context) - // { - // return visitExpression(node, context); - // } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/NormalizeOrExpressionRewriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/NormalizeOrExpressionRewriter.java index 6d00d1b72eb..ddd05f34ee5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/NormalizeOrExpressionRewriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/NormalizeOrExpressionRewriter.java @@ -43,18 +43,18 @@ import static org.apache.iotdb.db.relational.sql.tree.LogicalExpression.Operator public final class NormalizeOrExpressionRewriter { public static Expression normalizeOrExpression(Expression expression) { - return ExpressionTreeRewriter.rewriteWith(new Visitor(), expression); + return new Visitor().process(expression, null); } private NormalizeOrExpressionRewriter() {} - private static class Visitor extends ExpressionRewriter<Void> { + private static class Visitor extends RewritingVisitor<Void> { + @Override - public Expression rewriteLogicalExpression( - LogicalExpression node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { + public Expression visitLogicalExpression(LogicalExpression node, Void context) { List<Expression> terms = node.getTerms().stream() - .map(expression -> treeRewriter.rewrite(expression, context)) + .map(expression -> process(expression, context)) .collect(toImmutableList()); if (node.getOperator() == AND) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/RewritingVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/RewritingVisitor.java new file mode 100644 index 00000000000..64a87fa7bf7 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/RewritingVisitor.java @@ -0,0 +1,221 @@ +package org.apache.iotdb.db.queryengine.plan.relational.planner.ir; + +import org.apache.iotdb.db.relational.sql.tree.ArithmeticBinaryExpression; +import org.apache.iotdb.db.relational.sql.tree.BetweenPredicate; +import org.apache.iotdb.db.relational.sql.tree.Cast; +import org.apache.iotdb.db.relational.sql.tree.ComparisonExpression; +import org.apache.iotdb.db.relational.sql.tree.Expression; +import org.apache.iotdb.db.relational.sql.tree.FunctionCall; +import org.apache.iotdb.db.relational.sql.tree.Identifier; +import org.apache.iotdb.db.relational.sql.tree.InPredicate; +import org.apache.iotdb.db.relational.sql.tree.IsNotNullPredicate; +import org.apache.iotdb.db.relational.sql.tree.IsNullPredicate; +import org.apache.iotdb.db.relational.sql.tree.LikePredicate; +import org.apache.iotdb.db.relational.sql.tree.Literal; +import org.apache.iotdb.db.relational.sql.tree.LogicalExpression; +import org.apache.iotdb.db.relational.sql.tree.NotExpression; +import org.apache.iotdb.db.relational.sql.tree.NullIfExpression; +import org.apache.iotdb.db.relational.sql.tree.SymbolReference; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionTreeRewriter.sameElements; + +public class RewritingVisitor<C> extends IrVisitor<Expression, C> { + + @Override + protected Expression visitExpression(Expression node, C context) { + // RewritingVisitor must have explicit support for each expression type, with a dedicated + // visit method, + // so visitExpression() should never be called. + throw new UnsupportedOperationException( + "visit() not implemented for " + node.getClass().getName()); + } + + @Override + protected Expression visitArithmeticBinary(ArithmeticBinaryExpression node, C context) { + Expression left = process(node.getLeft(), context); + Expression right = process(node.getRight(), context); + + if (left != node.getLeft() || right != node.getRight()) { + // node.getLocation().get() may be null + return new ArithmeticBinaryExpression( + node.getLocation().get(), node.getOperator(), left, right); + } + + return node; + } + + @Override + protected Expression visitComparisonExpression(ComparisonExpression node, C context) { + Expression left = process(node.getLeft(), context); + Expression right = process(node.getRight(), context); + + if (left != node.getLeft() || right != node.getRight()) { + return new ComparisonExpression(node.getOperator(), left, right); + } + + return node; + } + + @Override + protected Expression visitBetweenPredicate(BetweenPredicate node, C context) { + Expression value = process(node.getValue(), context); + Expression min = process(node.getMin(), context); + Expression max = process(node.getMax(), context); + + if (value != node.getValue() || min != node.getMin() || max != node.getMax()) { + return new BetweenPredicate(value, min, max); + } + + return node; + } + + @Override + protected Expression visitLogicalExpression(LogicalExpression node, C context) { + List<Expression> terms = + node.getTerms().stream().map(term -> process(term, context)).collect(Collectors.toList()); + if (!sameElements(node.getTerms(), terms)) { + return new LogicalExpression(node.getOperator(), terms); + } + + return node; + } + + @Override + protected Expression visitNotExpression(NotExpression node, C context) { + Expression value = process(node.getValue(), context); + + if (value != node.getValue()) { + return new NotExpression(value); + } + + return node; + } + + @Override + protected Expression visitLikePredicate(LikePredicate node, C context) { + Expression value = process(node.getValue(), context); + Expression pattern = process(node.getPattern(), context); + Expression escape = + node.getEscape().isPresent() ? process(node.getEscape().get(), context) : null; + + if (value != node.getValue() + || pattern != node.getPattern() + || (escape != null && escape != node.getEscape().get())) { + return new LikePredicate(value, pattern, escape); + } + + return node; + } + + @Override + protected Expression visitIsNullPredicate(IsNullPredicate node, C context) { + Expression value = process(node.getValue(), context); + + if (value != node.getValue()) { + return new IsNullPredicate(value); + } + + return node; + } + + @Override + protected Expression visitIsNotNullPredicate(IsNotNullPredicate node, C context) { + Expression value = process(node.getValue(), context); + + if (value != node.getValue()) { + return new IsNotNullPredicate(value); + } + + return node; + } + + @Override + protected Expression visitNullIfExpression(NullIfExpression node, C context) { + Expression first = process(node.getFirst(), context); + Expression second = process(node.getSecond(), context); + + if (first != node.getFirst() || second != node.getSecond()) { + return new NullIfExpression(first, second); + } + + return node; + } + + // @Override + // protected Expression visitSearchedCaseExpression( + // SearchedCaseExpression node, C context) { + // ImmutableList.Builder<WhenClause> builder = ImmutableList.builder(); + // for (WhenClause expression : node.getWhenClauses()) { + // builder.add(process(expression, context)); + // } + // + // Optional<Expression> defaultValue = + // node.getDefaultValue().map(value -> rewrite(value, context.get())); + // + // if (!sameElements(node.getDefaultValue(), defaultValue) + // || !sameElements(node.getWhenClauses(), builder.build())) { + // // defaultValue.get() may be null + // return new SearchedCaseExpression(builder.build(), defaultValue.get()); + // } + // + // return node; + // } + + @Override + protected Expression visitFunctionCall(FunctionCall node, C context) { + List<Expression> arguments = + node.getArguments().stream() + .map(argument -> process(argument, context)) + .collect(Collectors.toList()); + + if (!sameElements(node.getArguments(), arguments)) { + return new FunctionCall(node.getName(), arguments); + } + return node; + } + + @Override + protected Expression visitInPredicate(InPredicate node, C context) { + Expression value = process(node.getValue(), context); + // List<Expression> values = node.getValueList().stream() + // .map(entry -> rewrite(entry, context.get())) + // .collect(toImmutableList()); + + if (node.getValue() != value + || !sameElements(Optional.of(value), Optional.of(node.getValue()))) { + return new InPredicate(value, value); + } + + return node; + } + + @Override + protected Expression visitCast(Cast node, C context) { + Expression expression = process(node.getExpression(), context); + + if (expression != node.getExpression()) { + return new Cast(expression, node.getType(), node.isSafe(), node.isTypeOnly()); + } + + return node; + } + + @Override + protected Expression visitSymbolReference(SymbolReference node, C context) { + return node; + } + + @Override + protected Expression visitIdentifier(Identifier node, C context) { + return node; + } + + @Override + protected Expression visitLiteral(Literal node, C context) { + return node; + } +}
