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 9e80bc0b006 fix SymbolReference, FieldReference;  add 
extractGlobalTimeFilter
     new 81815dd3f8e Merge branch 'ty/TableModelGrammar' of 
github.com:apache/iotdb into ty/TableModelGrammar
9e80bc0b006 is described below

commit 9e80bc0b00676d2fd52c8137a3a61d8502747ec5
Author: Beyyes <[email protected]>
AuthorDate: Tue Apr 16 23:32:23 2024 +0800

    fix SymbolReference, FieldReference;  add extractGlobalTimeFilter
---
 .../plan/relational/analyzer/Analysis.java         |   9 +
 .../plan/relational/planner/PlanBuilder.java       |  41 +-
 .../plan/relational/planner/PredicateUtils.java    | 415 +++++++++++++++++++++
 .../plan/relational/planner/QueryPlanner.java      |  22 +-
 .../relational/planner/node/TableScanNode.java     |   2 +-
 .../plan/relational/analyzer/AnalyzerTest.java     |   9 +-
 .../relational/planner/PredicateUtilsTest.java     |  52 +++
 .../db/relational/sql/tree/LogicalExpression.java  |   6 +-
 8 files changed, 538 insertions(+), 18 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
index 3465a6b45d2..e2d603fe479 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
@@ -28,6 +28,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.security.Identity;
 import org.apache.iotdb.db.relational.sql.tree.AllColumns;
+import org.apache.iotdb.db.relational.sql.tree.DataType;
 import org.apache.iotdb.db.relational.sql.tree.ExistsPredicate;
 import org.apache.iotdb.db.relational.sql.tree.Expression;
 import org.apache.iotdb.db.relational.sql.tree.FunctionCall;
@@ -171,6 +172,10 @@ public class Analysis implements IAnalysis {
     return namedQueries.get(NodeRef.of(table));
   }
 
+  public boolean isAnalyzed(Expression expression) {
+    return expression instanceof DataType || 
types.containsKey(NodeRef.of(expression));
+  }
+
   public void registerNamedQuery(Table tableReference, Query query) {
     requireNonNull(tableReference, "tableReference is null");
     requireNonNull(query, "query is null");
@@ -338,6 +343,10 @@ public class Analysis implements IAnalysis {
     return where.get(NodeRef.<Node>of(node));
   }
 
+  public Map<NodeRef<Node>, Expression> getWhereMap() {
+    return this.where;
+  }
+
   public void setOrderByExpressions(Node node, List<Expression> items) {
     orderByExpressions.put(NodeRef.of(node), ImmutableList.copyOf(items));
   }
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 49f93ed3e66..289f88acdc6 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
@@ -20,6 +20,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Scope;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.FieldReference;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -29,16 +30,21 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 public class PlanBuilder {
 
   private final PlanNode root;
 
-  public PlanBuilder(PlanNode root) {
+  // current mappings of underlying field -> symbol for translating direct 
field references
+  private final Symbol[] fieldSymbols;
+
+  public PlanBuilder(PlanNode root, Symbol[] fieldSymbols) {
     requireNonNull(root, "root is null");
 
     this.root = root;
+    this.fieldSymbols = fieldSymbols;
   }
 
   public static PlanBuilder newPlanBuilder(
@@ -51,21 +57,41 @@ public class PlanBuilder {
       Analysis analysis,
       Map<ScopeAware<Expression>, Symbol> mappings,
       SessionInfo session) {
-    return new PlanBuilder(plan.getRoot());
+    return new PlanBuilder(plan.getRoot(), plan.getFieldMappings().toArray(new 
Symbol[0]));
   }
 
   public PlanBuilder withNewRoot(PlanNode root) {
-    return new PlanBuilder(root);
+    return new PlanBuilder(root, fieldSymbols);
   }
 
   public PlanBuilder withScope(Scope scope, List<Symbol> fields) {
-    return new PlanBuilder(root);
+    return new PlanBuilder(root, fields.toArray(new Symbol[0]));
   }
 
   public PlanNode getRoot() {
     return root;
   }
 
+  public Symbol[] getFieldSymbols() {
+    return this.fieldSymbols;
+  }
+
+  public Symbol translate(Analysis analysis, Expression expression) {
+    verify(
+        analysis.isAnalyzed(expression),
+        "Expression is not analyzed (%s): %s",
+        expression.getClass().getName(),
+        expression);
+    Expression ret = translate(expression, true);
+    return Symbol.from(ret);
+  }
+
+  private Expression translate(Expression expression, boolean isRoot) {
+    if (expression instanceof FieldReference) {}
+
+    return expression;
+  }
+
   public <T extends Expression> PlanBuilder appendProjections(
       Iterable<T> expressions,
       Analysis analysis,
@@ -85,7 +111,9 @@ public class PlanBuilder {
     for (T expression : expressions) {
       // Skip any expressions that have already been translated and recorded 
in the
       // translation map, or that are duplicated in the list of exp
-      if (!mappings.containsKey(expression) && 
!set.contains(expression.toString())) {
+      if (!mappings.containsKey(expression)
+          && !set.contains(expression.toString())
+          && !(expression instanceof FieldReference)) {
         set.add(expression.toString());
         Symbol symbol = symbolAllocator.newSymbol("expr", 
analysis.getType(expression));
         projections.put(symbol, expression);
@@ -93,6 +121,7 @@ public class PlanBuilder {
       }
     }
 
-    return new PlanBuilder(new ProjectNode(idAllocator.genPlanNodeId(), root, 
projections.build()));
+    return new PlanBuilder(
+        new ProjectNode(idAllocator.genPlanNodeId(), root, 
projections.build()), fieldSymbols);
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
new file mode 100644
index 00000000000..0ae8c9444f5
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
@@ -0,0 +1,415 @@
+/*
+ * 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;
+
+import 
org.apache.iotdb.db.queryengine.plan.expression.UnknownExpressionTypeException;
+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.Identifier;
+import org.apache.iotdb.db.relational.sql.tree.InPredicate;
+import org.apache.iotdb.db.relational.sql.tree.LogicalExpression;
+import org.apache.iotdb.db.relational.sql.tree.LongLiteral;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.commons.jexl3.parser.ParserConstants.and;
+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 PredicateUtils {
+
+  private PredicateUtils() {
+    // util class
+  }
+
+  /**
+   * TODO consider more expression types
+   *
+   * <p>Extract global time predicate from query predicate.
+   *
+   * @param predicate raw query predicate
+   * @param canRewrite determined by the father of current expression
+   * @param isFirstOr whether it is the first LogicOrExpression encountered
+   * @return left is global time predicate, right is whether it has value 
filter
+   * @throws UnknownExpressionTypeException unknown expression type
+   */
+  public static Pair<Expression, Boolean> extractGlobalTimePredicate(
+      Expression predicate, boolean canRewrite, boolean isFirstOr) {
+    if (predicate instanceof LogicalExpression
+        && ((LogicalExpression) predicate).getOperator().equals(AND)) {
+      Pair<Expression, Boolean> leftResultPair =
+          extractGlobalTimePredicate(
+              ((LogicalExpression) predicate).getTerms().get(0), canRewrite, 
isFirstOr);
+      Pair<Expression, Boolean> rightResultPair =
+          extractGlobalTimePredicate(
+              ((LogicalExpression) predicate).getTerms().get(1), canRewrite, 
isFirstOr);
+
+      // 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 (canRewrite) {
+        LogicalExpression logicalExpression = (LogicalExpression) predicate;
+        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) {
+          logicalExpression.setTerms(
+              Arrays.asList(
+                  newLeftExpression != null
+                      ? newLeftExpression
+                      : logicalExpression.getTerms().get(0),
+                  newRightExpression != null
+                      ? newRightExpression
+                      : logicalExpression.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 (predicate instanceof LogicalExpression
+        && ((LogicalExpression) predicate).getOperator().equals(OR)) {
+      Pair<Expression, Boolean> leftResultPair =
+          extractGlobalTimePredicate(
+              ((LogicalExpression) predicate).getTerms().get(0), false, false);
+      Pair<Expression, Boolean> rightResultPair =
+          extractGlobalTimePredicate(
+              ((LogicalExpression) predicate).getTerms().get(1), false, false);
+
+      if (leftResultPair.left != null && rightResultPair.left != null) {
+        if (Boolean.TRUE.equals(isFirstOr && !leftResultPair.right && 
!rightResultPair.right)) {
+          ((LogicalExpression) predicate).getTerms().set(0, TRUE_LITERAL);
+          ((LogicalExpression) predicate).getTerms().set(0, TRUE_LITERAL);
+        }
+        return new Pair<>(
+            or(leftResultPair.left, rightResultPair.left),
+            leftResultPair.right || rightResultPair.right);
+      }
+      return new Pair<>(null, true);
+    }
+    //    else if 
(predicate.getExpressionType().equals(ExpressionType.LOGIC_NOT)) {
+    //      Pair<Expression, Boolean> childResultPair =
+    //          extractGlobalTimePredicate(
+    //              ((UnaryExpression) predicate).getExpression(), canRewrite, 
isFirstOr);
+    //      if (childResultPair.left != null) {
+    //        return new Pair<>(not(childResultPair.left), 
childResultPair.right);
+    //      }
+    //      return new Pair<>(null, true);
+    //    }
+    else if (predicate instanceof ComparisonExpression) {
+      Expression leftExpression = ((ComparisonExpression) predicate).getLeft();
+      Expression rightExpression = ((ComparisonExpression) 
predicate).getRight();
+      if (checkIsTimeFilter(leftExpression, rightExpression)
+          || checkIsTimeFilter(rightExpression, leftExpression)) {
+        return new Pair<>(predicate, false);
+      }
+      return new Pair<>(null, true);
+    }
+    //    else if (predicate instanceof LIKE)
+    //        || predicate.getExpressionType().equals(ExpressionType.REGEXP)) {
+    //      // time filter don't support LIKE and REGEXP
+    //      return new Pair<>(null, true);
+    //    }
+
+    //    else if (predicate instanceof BetweenPredicate) {
+    //      Expression firstExpression = ((TernaryExpression) 
predicate).getFirstExpression();
+    //      Expression secondExpression = ((TernaryExpression) 
predicate).getSecondExpression();
+    //      Expression thirdExpression = ((TernaryExpression) 
predicate).getThirdExpression();
+    //
+    //      boolean isTimeFilter = false;
+    //      if 
(firstExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+    //        isTimeFilter = checkBetweenConstantSatisfy(secondExpression, 
thirdExpression);
+    //      } else if 
(secondExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+    //        isTimeFilter = checkBetweenConstantSatisfy(firstExpression, 
thirdExpression);
+    //      } else if 
(thirdExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+    //        isTimeFilter = checkBetweenConstantSatisfy(secondExpression, 
firstExpression);
+    //      }
+    //      if (isTimeFilter) {
+    //        return new Pair<>(predicate, false);
+    //      }
+    //      return new Pair<>(null, true);
+    //    }
+
+    else if (predicate instanceof InPredicate) {
+      // time filter don't support IS_NULL
+      return new Pair<>(null, true);
+    }
+    //    else if (predicate.getExpressionType().equals(ExpressionType.IN)) {
+    //      Expression timeExpression = ((InExpression) 
predicate).getExpression();
+    //      if 
(timeExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
+    //        return new Pair<>(predicate, false);
+    //      }
+    //      return new Pair<>(null, true);
+    //    }
+    //    else if 
(predicate.getExpressionType().equals(ExpressionType.TIMESERIES)
+    //        || 
predicate.getExpressionType().equals(ExpressionType.CONSTANT)) {
+    //      return new Pair<>(null, true);
+    //    }
+    //    else if 
(predicate.getExpressionType().equals(ExpressionType.CASE_WHEN_THEN)) {
+    //      return new Pair<>(null, true);
+    //    }
+    //    else if 
(ExpressionType.FUNCTION.equals(predicate.getExpressionType())) {
+    //      return new Pair<>(null, true);
+    //    }
+    else {
+      throw new IllegalStateException(
+          "Unsupported expression in extractGlobalTimePredicate: " + 
predicate);
+    }
+  }
+
+  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.isConstantOperand()
+  //        && e2.isConstantOperand()
+  //        && ((ConstantOperand) e1).getDataType() == TSDataType.INT64
+  //        && ((ConstantOperand) e2).getDataType() == TSDataType.INT64
+  //        && (Long.parseLong(((ConstantOperand) e1).getValueString())
+  //            <= Long.parseLong(((ConstantOperand) e2).getValueString()));
+  //  }
+
+  /**
+   * Check if the given expression contains time filter.
+   *
+   * @param predicate given expression
+   * @return true if the given expression contains time filter
+   */
+  //  public static boolean checkIfTimeFilterExist(Expression predicate) {
+  //    return new TimeFilterExistChecker().process(predicate, null);
+  //  }
+
+  /**
+   * Recursively removes all use of the not() operator in a predicate by 
replacing all instances of
+   * not(x) with the inverse(x),
+   *
+   * <p>eg: not(and(eq(), not(eq(y))) -&gt; or(notEq(), eq(y))
+   *
+   * <p>The returned predicate should have the same meaning as the original, 
but without the use of
+   * the not() operator.
+   *
+   * <p>See also {@link PredicateUtils#reversePredicate(Expression)}, which is 
used to do the
+   * inversion.
+   *
+   * @param predicate the predicate to remove not() from
+   * @return the predicate with all not() operators removed
+   */
+  //  public static Expression predicateRemoveNot(Expression predicate) {
+  //    if (predicate.getExpressionType().equals(ExpressionType.LOGIC_AND)) {
+  //      return ExpressionFactory.and(
+  //          predicateRemoveNot(((BinaryExpression) 
predicate).getLeftExpression()),
+  //          predicateRemoveNot(((BinaryExpression) 
predicate).getRightExpression()));
+  //    } else if 
(predicate.getExpressionType().equals(ExpressionType.LOGIC_OR)) {
+  //      return ExpressionFactory.or(
+  //          predicateRemoveNot(((BinaryExpression) 
predicate).getLeftExpression()),
+  //          predicateRemoveNot(((BinaryExpression) 
predicate).getRightExpression()));
+  //    } else if 
(predicate.getExpressionType().equals(ExpressionType.LOGIC_NOT)) {
+  //      return reversePredicate(((LogicNotExpression) 
predicate).getExpression());
+  //    }
+  //    return predicate;
+  //  }
+
+  /**
+   * Converts a predicate to its logical inverse. The returned predicate 
should be equivalent to
+   * not(p), but without the use of a not() operator.
+   *
+   * <p>See also {@link PredicateUtils#predicateRemoveNot(Expression)}, which 
can remove the use of
+   * all not() operators without inverting the overall predicate.
+   *
+   * @param predicate given predicate
+   * @return the predicate after reversing
+   */
+  //  public static Expression reversePredicate(Expression predicate) {
+  //    return new ReversePredicateVisitor().process(predicate, null);
+  //  }
+
+  /**
+   * Simplify the given predicate (Remove the NULL and TRUE/FALSE expression).
+   *
+   * @param predicate given predicate
+   * @return the predicate after simplifying
+   */
+  //  public static Expression simplifyPredicate(Expression predicate) {
+  //    return new PredicateSimplifier().process(predicate, null);
+  //  }
+
+  /**
+   * Convert the given predicate to time filter.
+   *
+   * <p>Note: the supplied predicate must not contain any instances of the 
not() operator as this is
+   * not supported by this filter. The supplied predicate should first be run 
through {@link
+   * PredicateUtils#predicateRemoveNot(Expression)} to rewrite it in a form 
that doesn't make use of
+   * the not() operator.
+   *
+   * @param predicate given predicate
+   * @return the time filter converted from the given predicate
+   */
+  //  public static Filter convertPredicateToTimeFilter(Expression predicate) {
+  //    if (predicate == null) {
+  //      return null;
+  //    }
+  //    return predicate.accept(new ConvertPredicateToTimeFilterVisitor(), 
null);
+  //  }
+
+  //  public static Filter convertPredicateToFilter(
+  //      Expression predicate,
+  //      List<String> allMeasurements,
+  //      boolean isBuildPlanUseTemplate,
+  //      TypeProvider typeProvider) {
+  //    if (predicate == null) {
+  //      return null;
+  //    }
+  //    return predicate.accept(
+  //        new ConvertPredicateToFilterVisitor(),
+  //        new ConvertPredicateToFilterVisitor.Context(
+  //            allMeasurements, isBuildPlanUseTemplate, typeProvider));
+  //  }
+
+  /**
+   * Combine the given conjuncts into a single expression using "and".
+   *
+   * @param conjuncts given conjuncts
+   * @return the expression combined by the given conjuncts
+   */
+  public static Expression combineConjuncts(List<Expression> conjuncts) {
+    if (conjuncts.size() == 1) {
+      return conjuncts.get(0);
+    }
+    return constructRightDeepTreeWithAnd(conjuncts);
+  }
+
+  private static Expression constructRightDeepTreeWithAnd(List<Expression> 
conjuncts) {
+    // TODO: consider other structures of tree
+    if (conjuncts.size() == 2) {
+      return and(conjuncts.get(0), conjuncts.get(1));
+    } else {
+      return and(
+          conjuncts.get(0), constructRightDeepTreeWithAnd(conjuncts.subList(1, 
conjuncts.size())));
+    }
+  }
+
+  public static Expression removeDuplicateConjunct(Expression predicate) {
+    if (predicate == null) {
+      return null;
+    }
+    Set<Expression> conjuncts = new HashSet<>();
+    extractConjuncts(predicate, conjuncts);
+    return combineConjuncts(new ArrayList<>(conjuncts));
+  }
+
+  public static List<Expression> extractConjuncts(Expression predicate) {
+    Set<Expression> conjuncts = new HashSet<>();
+    extractConjuncts(predicate, conjuncts);
+    return new ArrayList<>(conjuncts);
+  }
+
+  private static void extractConjuncts(Expression predicate, Set<Expression> 
conjuncts) {
+    if (predicate instanceof LogicalExpression
+        && ((LogicalExpression) predicate).getOperator() == AND) {
+      extractConjuncts(((LogicalExpression) predicate).getTerms().get(0), 
conjuncts);
+      extractConjuncts(((LogicalExpression) predicate).getTerms().get(1), 
conjuncts);
+    } else {
+      conjuncts.add(predicate);
+    }
+  }
+
+  /**
+   * Extract the source symbol (full path for non-aligned path, device path 
for aligned path) from
+   * the given predicate. If the predicate contains multiple source symbols, 
return null.
+   *
+   * @param predicate given predicate
+   * @return the source symbol extracted from the given predicate
+   */
+  //  public static PartialPath extractPredicateSourceSymbol(Expression 
predicate) {
+  //    List<Expression> sourceExpressions = 
ExpressionAnalyzer.searchSourceExpressions(predicate);
+  //    Set<PartialPath> sourcePaths =
+  //        sourceExpressions.stream()
+  //            .map(expression -> ((TimeSeriesOperand) expression).getPath())
+  //            .collect(Collectors.toSet());
+  //    Iterator<PartialPath> pathIterator = sourcePaths.iterator();
+  //    MeasurementPath firstPath = (MeasurementPath) pathIterator.next();
+  //
+  //    if (sourcePaths.size() == 1) {
+  //      // only contain one source path, can be push down
+  //      return firstPath.isUnderAlignedEntity() ? firstPath.getDevicePath() 
: firstPath;
+  //    }
+  //
+  //    // sourcePaths contain more than one path, can be push down when
+  //    // these paths under on aligned device
+  //    if (!firstPath.isUnderAlignedEntity()) {
+  //      return null;
+  //    }
+  //    PartialPath checkedDevice = firstPath.getDevicePath();
+  //    while (pathIterator.hasNext()) {
+  //      MeasurementPath path = (MeasurementPath) pathIterator.next();
+  //      if (!path.isUnderAlignedEntity() || 
!path.getDevicePath().equals(checkedDevice)) {
+  //        return null;
+  //      }
+  //    }
+  //    return checkedDevice;
+  //  }
+
+  /**
+   * Check if the given predicate can be pushed down from FilterNode to 
ScanNode.
+   *
+   * <p>The predicate <b>cannot</b> be pushed down if it satisfies the 
following conditions:
+   * <li>predicate contains IS_NULL
+   *
+   * @param predicate given predicate
+   * @return true if the given predicate can be pushed down to source
+   */
+  //  public static boolean predicateCanPushDownToSource(Expression predicate) 
{
+  //    return new PredicateCanPushDownToSourceChecker().process(predicate, 
null);
+  //  }
+
+  /**
+   * Check if the given predicate can be pushed into ScanOperator and execute 
using the {@link
+   * Filter} interface.
+   *
+   * @param predicate given predicate
+   * @return true if the given predicate can be pushed into ScanOperator
+   */
+  //  public static boolean predicateCanPushIntoScan(Expression predicate) {
+  //    return new PredicatePushIntoScanChecker().process(predicate, null);
+  //  }
+}
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 616a7c5c2c1..f301a3cebec 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
@@ -24,6 +24,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode;
 import org.apache.iotdb.db.relational.sql.tree.Delete;
 import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.FieldReference;
 import org.apache.iotdb.db.relational.sql.tree.Node;
 import org.apache.iotdb.db.relational.sql.tree.Offset;
 import org.apache.iotdb.db.relational.sql.tree.OrderBy;
@@ -32,6 +33,7 @@ import org.apache.iotdb.db.relational.sql.tree.QueryBody;
 import org.apache.iotdb.db.relational.sql.tree.QuerySpecification;
 import org.apache.iotdb.db.relational.sql.tree.SortItem;
 import org.apache.iotdb.tsfile.read.common.type.Type;
+import org.apache.iotdb.tsfile.utils.Pair;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -47,6 +49,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;
 
 public class QueryPlanner {
   private final Analysis analysis;
@@ -104,7 +107,7 @@ public class QueryPlanner {
     builder = builder.appendProjections(outputs, analysis, symbolAllocator, 
idAllocator);
 
     return new RelationPlan(
-        builder.getRoot(), analysis.getScope(query), computeOutputs(builder, 
outputs));
+        builder.getRoot(), analysis.getScope(query), computeOutputs(builder, 
analysis, outputs));
   }
 
   public RelationPlan plan(QuerySpecification node) {
@@ -171,7 +174,7 @@ public class QueryPlanner {
     builder = builder.appendProjections(outputs, analysis, symbolAllocator, 
idAllocator);
 
     return new RelationPlan(
-        builder.getRoot(), analysis.getScope(node), computeOutputs(builder, 
outputs));
+        builder.getRoot(), analysis.getScope(node), computeOutputs(builder, 
analysis, outputs));
 
     // TODO handle aggregate, having, distinct, subQuery later
   }
@@ -201,10 +204,17 @@ public class QueryPlanner {
   }
 
   private static List<Symbol> computeOutputs(
-      PlanBuilder builder, List<Expression> outputExpressions) {
+      PlanBuilder builder, Analysis analysis, List<Expression> 
outputExpressions) {
     ImmutableList.Builder<Symbol> outputSymbols = ImmutableList.builder();
     for (Expression expression : outputExpressions) {
-      outputSymbols.add(new Symbol(expression.toString()));
+      // Symbol symbol = builder.translate(analysis, expression);
+      // outputSymbols.add(symbol);
+      Symbol symbol = null;
+      if (expression instanceof FieldReference) {
+        FieldReference reference = (FieldReference) expression;
+        symbol = builder.getFieldSymbols()[reference.getFieldIndex()];
+      }
+      outputSymbols.add(symbol != null ? symbol : new 
Symbol(expression.toString()));
     }
     return outputSymbols.build();
   }
@@ -233,10 +243,12 @@ public class QueryPlanner {
       return subPlan;
     }
 
-    // subPlan = subqueryPlanner.handleSubqueries(subPlan, predicate, 
analysis.getSubqueries(node));
+    Pair<Expression, Boolean> ret = extractGlobalTimePredicate(predicate, 
true, true);
 
     return subPlan.withNewRoot(
         new FilterNode(idAllocator.genPlanNodeId(), subPlan.getRoot(), 
predicate));
+
+    // subPlan = subqueryPlanner.handleSubqueries(subPlan, predicate, 
analysis.getSubqueries(node));
   }
 
   public static Expression coerceIfNecessary(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
index 7af35991103..ca271871f5b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java
@@ -26,7 +26,7 @@ public class TableScanNode extends PlanNode {
   private final Map<Symbol, ColumnSchema> assignments;
 
   private List<DeviceEntry> deviceEntries;
-  private Map<Symbol, Integer> attributesMap;
+  private Map<Symbol, Integer> idAndAttributeIndexMap;
 
   // The order to traverse the data.
   // Currently, we only support TIMESTAMP_ASC and TIMESTAMP_DESC here.
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index 8bb2cecd3bc..34eca515305 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -60,9 +60,7 @@ import static org.mockito.ArgumentMatchers.eq;
 
 public class AnalyzerTest {
 
-  private final SqlParser sqlParser = new SqlParser();
-
-  private final NopAccessControl nopAccessControl = new NopAccessControl();
+  private static final NopAccessControl nopAccessControl = new 
NopAccessControl();
 
   @Test
   public void testMockQuery() throws OperatorNotFoundException {
@@ -133,7 +131,7 @@ public class AnalyzerTest {
   @Test
   public void testSingleTableQuery() throws IoTDBException {
     // no sort
-    String sql = "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 ";
+    String sql = "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 where 
time>1 and s1>1";
     // + "WHERE time>1 AND tag1='A' OR s2>3";
     Metadata metadata = new TestMatadata();
 
@@ -151,8 +149,9 @@ public class AnalyzerTest {
     System.out.println(result);
   }
 
-  private Analysis analyzeSQL(String sql, Metadata metadata) {
+  public static Analysis analyzeSQL(String sql, Metadata metadata) {
     try {
+      SqlParser sqlParser = new SqlParser();
       Statement statement = sqlParser.createStatement(sql);
       SessionInfo session = new SessionInfo(0, "test", ZoneId.systemDefault(), 
"testdb");
       StatementAnalyzerFactory statementAnalyzerFactory =
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
new file mode 100644
index 00000000000..cb369a8839c
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestMatadata;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
+import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import org.junit.Test;
+
+import static 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.AnalyzerTest.analyzeSQL;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate;
+
+public class PredicateUtilsTest {
+  @Test
+  public void extractGlobalTimePredicateTest() {
+    String sql = "SELECT tag1 FROM table1 where time>1 and s1>1";
+    Metadata metadata = new TestMatadata();
+
+    Analysis actualAnalysis = analyzeSQL(sql, metadata);
+    Pair<Expression, Boolean> ret =
+        extractGlobalTimePredicate(
+            actualAnalysis.getWhereMap().values().iterator().next(), true, 
true);
+    System.out.println(ret.getLeft());
+
+    sql = "SELECT tag1 FROM table1 where time>1 and s1>1 or tag1='A'";
+    actualAnalysis = analyzeSQL(sql, metadata);
+    ret =
+        extractGlobalTimePredicate(
+            actualAnalysis.getWhereMap().values().iterator().next(), true, 
true);
+    System.out.println(ret.getLeft());
+  }
+}
diff --git 
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
index c99c764e56d..a5eea3e4a77 100644
--- 
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
+++ 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/LogicalExpression.java
@@ -45,7 +45,7 @@ public class LogicalExpression extends Expression {
   }
 
   private final Operator operator;
-  private final List<Expression> terms;
+  private List<Expression> terms;
 
   public LogicalExpression(Operator operator, List<Expression> terms) {
     super(null);
@@ -69,6 +69,10 @@ public class LogicalExpression extends Expression {
     return terms;
   }
 
+  public void setTerms(List<Expression> terms) {
+    this.terms = ImmutableList.copyOf(terms);
+  }
+
   @Override
   public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
     return visitor.visitLogicalExpression(this, context);


Reply via email to