This is an automated email from the ASF dual-hosted git repository.

caogaofei pushed a commit to branch ty/TableModelGrammar
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/ty/TableModelGrammar by this 
push:
     new c74f552733b add bewteen and, is null, is not null, substring, like, 
round
     new 4392c97a181 Merge branch 'ty/TableModelGrammar' of 
github.com:apache/iotdb into ty/TableModelGrammar
c74f552733b is described below

commit c74f552733b4007e235a678a610d57c9e6ee3262
Author: Beyyes <[email protected]>
AuthorDate: Sat Apr 27 10:27:44 2024 +0800

    add bewteen and, is null, is not null, substring, like, round
---
 .../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 ++++++++++++++++++
 10 files changed, 552 insertions(+), 175 deletions(-)

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;
+  }
+}


Reply via email to