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

jackietien 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 bf2f741a8fa Add TranslationMap and support of subquery analyze
bf2f741a8fa is described below

commit bf2f741a8fab5c45e69529778863c83750d5aa5c
Author: Weihao Li <[email protected]>
AuthorDate: Tue Jun 25 09:35:24 2024 +0800

    Add TranslationMap and support of subquery analyze
---
 .../plan/relational/planner/PlanBuilder.java       | 124 ++++----
 .../plan/relational/planner/QueryPlanner.java      |  63 ++--
 .../plan/relational/planner/RelationPlanner.java   |   4 +-
 .../plan/relational/planner/SymbolAllocator.java   |  24 ++
 .../plan/relational/planner/TranslationMap.java    | 334 +++++++++++++++++++++
 .../relational/planner/ir/ExpressionRewriter.java  |  23 ++
 .../planner/ir/ExpressionTranslateVisitor.java     | 149 ---------
 .../planner/ir/ExpressionTreeRewriter.java         |  50 +++
 .../plan/relational/planner/ir/IrVisitor.java      |   5 +
 .../planner/optimizations/FilterScanCombine.java   |   7 +-
 .../plan/relational/sql/ast/LikePredicate.java     |   2 +-
 .../plan/relational/analyzer/AnalyzerTest.java     |  11 +-
 12 files changed, 537 insertions(+), 259 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 201fa6c4d03..fb1729480f5 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
@@ -16,52 +16,72 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 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.analyzer.ResolvedField;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Scope;
-import 
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionTranslateVisitor;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableMetadataImpl;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FieldReference;
+import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
+
+import com.google.common.collect.ImmutableMap;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
 
 import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.ScopeAware.scopeAwareKey;
 
 public class PlanBuilder {
 
+  private final TranslationMap translations;
   private final PlanNode root;
 
-  private final Analysis analysis;
-
-  // current mappings of underlying field -> symbol for translating direct 
field references
-  private final Symbol[] fieldSymbols;
-
-  public PlanBuilder(PlanNode root, Analysis analysis, Symbol[] fieldSymbols) {
+  public PlanBuilder(TranslationMap translations, PlanNode root) {
+    requireNonNull(translations, "translations is null");
     requireNonNull(root, "root is null");
 
+    this.translations = translations;
     this.root = root;
-    this.analysis = analysis;
-    this.fieldSymbols = fieldSymbols;
   }
 
   public static PlanBuilder newPlanBuilder(RelationPlan plan, Analysis 
analysis) {
+    return newPlanBuilder(
+        plan,
+        analysis,
+        ImmutableMap.of(),
+        new PlannerContext(new TableMetadataImpl(), new 
InternalTypeManager()));
+  }
+
+  public static PlanBuilder newPlanBuilder(
+      RelationPlan plan,
+      Analysis analysis,
+      Map<ScopeAware<Expression>, Symbol> mappings,
+      PlannerContext plannerContext) {
     return new PlanBuilder(
-        plan.getRoot(), analysis, plan.getFieldMappings().toArray(new 
Symbol[0]));
+        new TranslationMap(
+            Optional.empty(),
+            plan.getScope(),
+            analysis,
+            plan.getFieldMappings(),
+            mappings,
+            plannerContext),
+        plan.getRoot());
   }
 
   public PlanBuilder withNewRoot(PlanNode root) {
-    return new PlanBuilder(root, this.analysis, this.fieldSymbols);
+    return new PlanBuilder(translations, root);
   }
 
   public PlanBuilder withScope(Scope scope, List<Symbol> fields) {
-    return new PlanBuilder(root, this.analysis, fields.toArray(new Symbol[0]));
+    return new PlanBuilder(translations.withScope(scope, fields), root);
+  }
+
+  public TranslationMap getTranslations() {
+    return translations;
   }
 
   public PlanNode getRoot() {
@@ -69,67 +89,54 @@ public class PlanBuilder {
   }
 
   public Symbol[] getFieldSymbols() {
-    return this.fieldSymbols;
+    return translations.getFieldSymbols();
+  }
+
+  public Symbol translate(Expression expression) {
+    return Symbol.from(translations.rewrite(expression));
   }
 
   public Expression rewrite(Expression root) {
     verify(
-        analysis.isAnalyzed(root),
+        translations.getAnalysis().isAnalyzed(root),
         "Expression is not analyzed (%s): %s",
         root.getClass().getName(),
         root);
-    return translate(root);
+    return translations.rewrite(root);
   }
 
-  private Expression translate(Expression expression) {
-    return ExpressionTranslateVisitor.translateToSymbolReference(expression, 
this);
-  }
-
-  public Optional<Symbol> getSymbolForColumn(Expression expression) {
-    if (!analysis.isColumnReference(expression)) {
-      // Expression can be a reference to lambda argument (or 
DereferenceExpression based on lambda
-      // argument reference).
-      // In such case, the expression might still be resolvable with 
plan.getScope() but we should
-      // not resolve it.
-      return Optional.empty();
-    }
-
-    ResolvedField field = 
analysis.getColumnReferenceFields().get(NodeRef.of(expression));
-
-    if (field != null) {
-      return Optional.of(fieldSymbols[field.getHierarchyFieldIndex()]);
-    }
-
-    return Optional.empty();
+  public <T extends Expression> PlanBuilder appendProjections(
+      Iterable<T> expressions, SymbolAllocator symbolAllocator, 
MPPQueryContext queryContext) {
+    return appendProjections(
+        expressions,
+        symbolAllocator,
+        queryContext,
+        TranslationMap::rewrite,
+        TranslationMap::canTranslate);
   }
 
   public <T extends Expression> PlanBuilder appendProjections(
       Iterable<T> expressions,
-      Analysis analysis,
       SymbolAllocator symbolAllocator,
-      MPPQueryContext queryContext) {
+      MPPQueryContext queryContext,
+      BiFunction<TranslationMap, T, Expression> rewriter,
+      BiPredicate<TranslationMap, T> alreadyHasTranslation) {
     Assignments.Builder projections = Assignments.builder();
 
     // add an identity projection for underlying plan
     projections.putIdentities(root.getOutputSymbols());
-
-    Set<String> symbolSet =
-        
root.getOutputSymbols().stream().map(Symbol::getName).collect(Collectors.toSet());
-
-    Map<Expression, Symbol> mappings = new HashMap<>();
+    Analysis analysis = translations.getAnalysis();
+    Map<ScopeAware<Expression>, Symbol> mappings = new HashMap<>();
     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)
-          && !symbolSet.contains(expression.toString().toLowerCase())
-          && !(expression instanceof FieldReference)) {
-        symbolSet.add(expression.toString());
-        // Symbol symbol = symbolAllocator.newSymbol("expr", 
analysis.getType(expression));
+      // 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(scopeAwareKey(expression, analysis, 
translations.getScope()))
+          && !alreadyHasTranslation.test(translations, expression)) {
         Symbol symbol =
             symbolAllocator.newSymbol(expression.toString(), 
analysis.getType(expression));
         queryContext.getTypeProvider().putTableModelType(symbol, 
analysis.getType(expression));
-        projections.put(symbol, translate(expression));
-        mappings.put(expression, symbol);
+        projections.put(symbol, rewriter.apply(translations, expression));
+        mappings.put(scopeAwareKey(expression, analysis, 
translations.getScope()), symbol);
       }
     }
 
@@ -138,8 +145,7 @@ public class PlanBuilder {
     }
 
     return new PlanBuilder(
-        new ProjectNode(queryContext.getQueryId().genPlanNodeId(), this.root, 
projections.build()),
-        this.analysis,
-        this.fieldSymbols);
+        getTranslations().withAdditionalMappings(mappings),
+        new ProjectNode(queryContext.getQueryId().genPlanNodeId(), root, 
projections.build()));
   }
 }
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 678f7cc25ff..a44ee2f7bf6 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,8 +19,6 @@ 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.analyzer.predicate.ConvertPredicateToTimeFilterVisitor;
-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;
@@ -39,8 +37,8 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SortItem;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import org.apache.tsfile.read.common.type.Type;
-import org.apache.tsfile.utils.Pair;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -51,7 +49,6 @@ 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.ir.GlobalTimePredicateExtractVisitor.extractGlobalTimeFilter;
 
 public class QueryPlanner {
   private final Analysis analysis;
@@ -98,7 +95,7 @@ public class QueryPlanner {
     if (orderBy.size() > 0) {
       builder =
           builder.appendProjections(
-              Iterables.concat(orderBy, outputs), analysis, symbolAllocator, 
queryContext);
+              Iterables.concat(orderBy, outputs), symbolAllocator, 
queryContext);
     }
 
     Optional<OrderingScheme> orderingScheme =
@@ -106,7 +103,7 @@ public class QueryPlanner {
     builder = sort(builder, orderingScheme);
     builder = offset(builder, query.getOffset());
     builder = limit(builder, query.getLimit(), orderingScheme);
-    builder = builder.appendProjections(outputs, analysis, symbolAllocator, 
queryContext);
+    builder = builder.appendProjections(outputs, symbolAllocator, 
queryContext);
 
     return new RelationPlan(
         builder.getRoot(), analysis.getScope(query), computeOutputs(builder, 
outputs));
@@ -127,7 +124,7 @@ public class QueryPlanner {
 
       // pre-project the folded expressions to preserve any non-deterministic 
semantics of functions
       // that might be referenced
-      builder = builder.appendProjections(expressions, analysis, 
symbolAllocator, queryContext);
+      builder = builder.appendProjections(expressions, symbolAllocator, 
queryContext);
     }
 
     List<Expression> outputs = outputExpressions(selectExpressions);
@@ -139,34 +136,30 @@ public class QueryPlanner {
         // translated
         // aggregations are visible.
         List<Expression> orderByAggregates = 
analysis.getOrderByAggregates(node.getOrderBy().get());
-        builder =
-            builder.appendProjections(orderByAggregates, analysis, 
symbolAllocator, queryContext);
+        builder = builder.appendProjections(orderByAggregates, 
symbolAllocator, queryContext);
       }
 
       // Add projections for the outputs of SELECT, but stack them on top of 
the ones from the FROM
       // clause so both are visible
       // when resolving the ORDER BY clause.
-      // TODO this appendProjections may be removed
-      builder = builder.appendProjections(outputs, analysis, symbolAllocator, 
queryContext);
+      builder = builder.appendProjections(outputs, symbolAllocator, 
queryContext);
 
       // The new scope is the composite of the fields from the FROM and SELECT 
clause (local nested
       // scopes). Fields from the bottom of
       // the scope stack need to be placed first to match the expected layout 
for nested scopes.
-      // List<Symbol> newFields = new ArrayList<>();
-      // newFields.addAll(builder.getTranslations().getFieldSymbols());
+      List<Symbol> newFields = new ArrayList<>();
+      newFields.addAll(builder.getTranslations().getFieldSymbolsList());
 
-      //            outputs.stream()
-      //                    .map(builder::translate)
-      //                    .forEach(newFields::add);
+      outputs.stream().map(builder::translate).forEach(newFields::add);
 
-      // builder = 
builder.withScope(analysis.getScope(node.getOrderBy().get()), newFields);
+      builder = builder.withScope(analysis.getScope(node.getOrderBy().get()), 
newFields);
     }
 
     List<Expression> orderBy = analysis.getOrderByExpressions(node);
-    if (!orderBy.isEmpty()) {
+    if (orderBy.size() > 0) {
       builder =
           builder.appendProjections(
-              Iterables.concat(orderBy, outputs), analysis, symbolAllocator, 
queryContext);
+              Iterables.concat(orderBy, outputs), symbolAllocator, 
queryContext);
     }
 
     Optional<OrderingScheme> orderingScheme =
@@ -175,7 +168,7 @@ public class QueryPlanner {
     builder = offset(builder, node.getOffset());
     builder = limit(builder, node.getLimit(), orderingScheme);
 
-    builder = builder.appendProjections(outputs, analysis, symbolAllocator, 
queryContext);
+    builder = builder.appendProjections(outputs, symbolAllocator, 
queryContext);
 
     return new RelationPlan(
         builder.getRoot(), analysis.getScope(node), computeOutputs(builder, 
outputs));
@@ -240,34 +233,16 @@ public class QueryPlanner {
     }
   }
 
-  private PlanBuilder filter(PlanBuilder planBuilder, Expression predicate) {
+  private PlanBuilder filter(PlanBuilder subPlan, Expression predicate) {
     if (predicate == null) {
-      return planBuilder;
-    }
-
-    Pair<Expression, Boolean> resultPair = extractGlobalTimeFilter(predicate);
-    Expression globalTimePredicate = null;
-    if (resultPair.left != null) {
-      globalTimePredicate =
-          
ExpressionTranslateVisitor.translateToSymbolReference(resultPair.left, 
planBuilder);
-
-      queryContext.setGlobalTimeFilter(
-          globalTimePredicate.accept(new 
ConvertPredicateToTimeFilterVisitor(), null));
-    }
-    boolean hasValueFilter = resultPair.right;
-    if (!hasValueFilter) {
-      return planBuilder;
+      return subPlan;
     }
-    analysis.setHasValueFilter(true);
-    // TODO if predicate equals TrueConstant, no need filter
 
-    return planBuilder.withNewRoot(
+    // planBuilder = subqueryPlanner.handleSubqueries(subPlan, predicate,
+    // analysis.getSubqueries(node));
+    return subPlan.withNewRoot(
         new FilterNode(
-            queryIdAllocator.genPlanNodeId(),
-            planBuilder.getRoot(),
-            planBuilder.rewrite(predicate)));
-
-    // subPlan = subqueryPlanner.handleSubqueries(subPlan, predicate, 
analysis.getSubqueries(node));
+            queryIdAllocator.genPlanNodeId(), subPlan.getRoot(), 
subPlan.rewrite(predicate)));
   }
 
   public static Expression coerceIfNecessary(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
index c0386bcbbb2..cedde9533c9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java
@@ -138,7 +138,9 @@ public class RelationPlanner extends 
AstVisitor<RelationPlan, Void> {
   // ================================ Implemented later 
=====================================
   @Override
   protected RelationPlan visitTableSubquery(TableSubquery node, Void context) {
-    throw new IllegalStateException("TableSubquery is not supported in current 
version.");
+    RelationPlan plan = process(node.getQuery(), context);
+    // TODO transmit outerContext
+    return new RelationPlan(plan.getRoot(), analysis.getScope(node), 
plan.getFieldMappings());
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/SymbolAllocator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/SymbolAllocator.java
index afbdc6e15e3..13c1f6bb0d8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/SymbolAllocator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/SymbolAllocator.java
@@ -15,6 +15,10 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner;
 
 import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Field;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference;
 
 import org.apache.tsfile.read.common.type.Type;
 
@@ -51,6 +55,26 @@ public class SymbolAllocator {
     return symbol;
   }
 
+  public Symbol newSymbol(Expression expression, Type type) {
+    return newSymbol(expression, type, null);
+  }
+
+  public Symbol newSymbol(Expression expression, Type type, String suffix) {
+    String nameHint = "expr";
+    if (expression instanceof Identifier) {
+      nameHint = ((Identifier) expression).getValue();
+    } else if (expression instanceof FunctionCall) {
+      nameHint = ((FunctionCall) expression).getName().getSuffix();
+    } else if (expression instanceof SymbolReference) {
+      nameHint = ((SymbolReference) expression).getName();
+    }
+    /*else if (expression instanceof GroupingOperation) {
+      nameHint = "grouping";
+    }*/
+
+    return newSymbol(nameHint, type, suffix);
+  }
+
   public Symbol newSymbol(Field field) {
     String symbolHint = field.getName().orElse("field");
     return newSymbol(symbolHint, field.getType());
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TranslationMap.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TranslationMap.java
new file mode 100644
index 00000000000..ea1a78a5573
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TranslationMap.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed 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.NodeRef;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.ResolvedField;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Scope;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionRewriter;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExpressionTreeRewriter;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FieldReference;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LikePredicate;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.util.AstUtil;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.ScopeAware.scopeAwareKey;
+
+/**
+ * Keeps mappings of fields and AST expressions to symbols in the current plan 
within query
+ * boundary.
+ *
+ * <p>AST and IR expressions use the same class hierarchy ({@link
+ * org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression}, but 
differ in the following
+ * ways:
+ * <li>AST expressions contain Identifiers, while IR expressions contain 
SymbolReferences
+ * <li>FunctionCalls in AST expressions are SQL function names. In IR 
expressions, they contain an
+ *     encoded name representing a resolved function
+ */
+public class TranslationMap {
+  // all expressions are rewritten in terms of fields declared by this 
relation plan
+  private final Scope scope;
+  private final Analysis analysis;
+  private final Optional<TranslationMap> outerContext;
+  // TODO unused now
+  private final PlannerContext plannerContext;
+
+  // current mappings of underlying field -> symbol for translating direct 
field references
+  private final Symbol[] fieldSymbols;
+
+  // current mappings of sub-expressions -> symbol
+  private final Map<ScopeAware<Expression>, Symbol> astToSymbols;
+  // TODO unused now
+  private final Map<NodeRef<Expression>, Symbol> substitutions;
+
+  public TranslationMap(
+      Optional<TranslationMap> outerContext,
+      Scope scope,
+      Analysis analysis,
+      List<Symbol> fieldSymbols,
+      PlannerContext plannerContext) {
+    this(
+        outerContext,
+        scope,
+        analysis,
+        fieldSymbols.toArray(new Symbol[0]).clone(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        plannerContext);
+  }
+
+  public TranslationMap(
+      Optional<TranslationMap> outerContext,
+      Scope scope,
+      Analysis analysis,
+      List<Symbol> fieldSymbols,
+      Map<ScopeAware<Expression>, Symbol> astToSymbols,
+      PlannerContext plannerContext) {
+    this(
+        outerContext,
+        scope,
+        analysis,
+        fieldSymbols.toArray(new Symbol[0]),
+        astToSymbols,
+        ImmutableMap.of(),
+        plannerContext);
+  }
+
+  public TranslationMap(
+      Optional<TranslationMap> outerContext,
+      Scope scope,
+      Analysis analysis,
+      Symbol[] fieldSymbols,
+      Map<ScopeAware<Expression>, Symbol> astToSymbols,
+      Map<NodeRef<Expression>, Symbol> substitutions,
+      PlannerContext plannerContext) {
+    this.outerContext = requireNonNull(outerContext, "outerContext is null");
+    this.scope = requireNonNull(scope, "scope is null");
+    this.analysis = requireNonNull(analysis, "analysis is null");
+    this.plannerContext = requireNonNull(plannerContext, "plannerContext is 
null");
+    this.substitutions = ImmutableMap.copyOf(substitutions);
+
+    requireNonNull(fieldSymbols, "fieldSymbols is null");
+    this.fieldSymbols = fieldSymbols.clone();
+
+    requireNonNull(astToSymbols, "astToSymbols is null");
+    this.astToSymbols = ImmutableMap.copyOf(astToSymbols);
+
+    checkArgument(
+        scope.getLocalScopeFieldCount() == fieldSymbols.length,
+        "scope: %s, fields mappings: %s",
+        scope.getRelationType().getAllFieldCount(),
+        fieldSymbols.length);
+
+    astToSymbols.keySet().stream()
+        .map(ScopeAware::getNode)
+        .forEach(TranslationMap::verifyAstExpression);
+  }
+
+  public TranslationMap withScope(Scope scope, List<Symbol> fields) {
+    return new TranslationMap(
+        outerContext,
+        scope,
+        analysis,
+        fields.toArray(new Symbol[0]),
+        astToSymbols,
+        substitutions,
+        plannerContext);
+  }
+
+  public TranslationMap withNewMappings(
+      Map<ScopeAware<Expression>, Symbol> mappings, List<Symbol> fields) {
+    return new TranslationMap(outerContext, scope, analysis, fields, mappings, 
plannerContext);
+  }
+
+  public TranslationMap withAdditionalMappings(Map<ScopeAware<Expression>, 
Symbol> mappings) {
+    Map<ScopeAware<Expression>, Symbol> newMappings = new HashMap<>();
+    newMappings.putAll(this.astToSymbols);
+    newMappings.putAll(mappings);
+
+    return new TranslationMap(
+        outerContext, scope, analysis, fieldSymbols, newMappings, 
substitutions, plannerContext);
+  }
+
+  public TranslationMap 
withAdditionalIdentityMappings(Map<NodeRef<Expression>, Symbol> mappings) {
+    Map<NodeRef<Expression>, Symbol> newMappings = new HashMap<>();
+    newMappings.putAll(this.substitutions);
+    newMappings.putAll(mappings);
+
+    return new TranslationMap(
+        outerContext, scope, analysis, fieldSymbols, astToSymbols, 
newMappings, plannerContext);
+  }
+
+  public List<Symbol> getFieldSymbolsList() {
+    return Collections.unmodifiableList(Arrays.asList(fieldSymbols));
+  }
+
+  public Symbol[] getFieldSymbols() {
+    return fieldSymbols;
+  }
+
+  public Map<ScopeAware<Expression>, Symbol> getMappings() {
+    return astToSymbols;
+  }
+
+  public Analysis getAnalysis() {
+    return analysis;
+  }
+
+  public boolean canTranslate(Expression expression) {
+    verifyAstExpression(expression);
+
+    if (astToSymbols.containsKey(scopeAwareKey(expression, analysis, scope))
+        || substitutions.containsKey(NodeRef.of(expression))
+        || expression instanceof FieldReference) {
+      return true;
+    }
+
+    if (analysis.isColumnReference(expression)) {
+      ResolvedField field = 
analysis.getColumnReferenceFields().get(NodeRef.of(expression));
+      return scope.isLocalScope(field.getScope());
+    }
+
+    return false;
+  }
+
+  public Expression rewrite(Expression expression) {
+    verifyAstExpression(expression);
+    verify(
+        analysis.isAnalyzed(expression),
+        "Expression is not analyzed (%s): %s",
+        expression.getClass().getName(),
+        expression);
+
+    return ExpressionTreeRewriter.rewriteWith(
+        new ExpressionRewriter<Void>() {
+          @Override
+          protected Expression rewriteExpression(
+              Expression node, Void context, ExpressionTreeRewriter<Void> 
treeRewriter) {
+            Optional<SymbolReference> mapped = tryGetMapping(node);
+            if (mapped.isPresent()) {
+              return mapped.get();
+            }
+
+            return treeRewriter.defaultRewrite(node, context);
+          }
+
+          @Override
+          public Expression rewriteFieldReference(
+              FieldReference node, Void context, ExpressionTreeRewriter<Void> 
treeRewriter) {
+            Optional<SymbolReference> mapped = tryGetMapping(node);
+            if (mapped.isPresent()) {
+              return mapped.get();
+            }
+
+            return getSymbolForColumn(node)
+                .map(Symbol::toSymbolReference)
+                .orElseThrow(
+                    () ->
+                        new IllegalStateException(
+                            format(
+                                "No symbol mapping for node '%s' (%s)",
+                                node, node.getFieldIndex())));
+          }
+
+          @Override
+          public Expression rewriteIdentifier(
+              Identifier node, Void context, ExpressionTreeRewriter<Void> 
treeRewriter) {
+            Optional<SymbolReference> mapped = tryGetMapping(node);
+            if (mapped.isPresent()) {
+              return mapped.get();
+            }
+
+            return getSymbolForColumn(node)
+                .map(symbol -> (Expression) symbol.toSymbolReference())
+                .orElseGet(() -> node);
+          }
+
+          @Override
+          public Expression rewriteFunctionCall(
+              FunctionCall node, Void context, ExpressionTreeRewriter<Void> 
treeRewriter) {
+            Optional<SymbolReference> mapped = tryGetMapping(node);
+            if (mapped.isPresent()) {
+              return mapped.get();
+            }
+
+            // ResolvedFunction resolvedFunction = 
analysis.getResolvedFunction(node);
+            // checkArgument(resolvedFunction != null, "Function has not been 
analyzed: %s", node);
+
+            List<Expression> newArguments =
+                node.getArguments().stream()
+                    .map(argument -> rewrite(argument))
+                    .collect(Collectors.toList());
+            return new FunctionCall(node.getName(), node.isDistinct(), 
newArguments);
+          }
+
+          @Override
+          public Expression rewriteLikePredicate(
+              LikePredicate node, Void context, ExpressionTreeRewriter<Void> 
treeRewriter) {
+            Optional<SymbolReference> mapped = tryGetMapping(node);
+            if (mapped.isPresent()) {
+              return mapped.get();
+            }
+            Expression value = treeRewriter.rewrite(node.getValue(), context);
+            Expression pattern = treeRewriter.rewrite(node.getPattern(), 
context);
+            Optional<Expression> escape =
+                node.getEscape().map(e -> treeRewriter.rewrite(e, context));
+            return escape.isPresent()
+                ? new LikePredicate(value, pattern, escape.get())
+                : new LikePredicate(value, pattern, null);
+          }
+        },
+        expression);
+  }
+
+  public Optional<SymbolReference> tryGetMapping(Expression expression) {
+    Symbol symbol = substitutions.get(NodeRef.of(expression));
+    if (symbol == null) {
+      symbol = astToSymbols.get(scopeAwareKey(expression, analysis, scope));
+    }
+
+    return Optional.ofNullable(symbol).map(Symbol::toSymbolReference);
+  }
+
+  public Optional<Symbol> getSymbolForColumn(Expression expression) {
+    if (!analysis.isColumnReference(expression)) {
+      // Expression can be a reference to lambda argument (or 
DereferenceExpression based on lambda
+      // argument reference).
+      // In such case, the expression might still be resolvable with 
plan.getScope() but we should
+      // not resolve it.
+      return Optional.empty();
+    }
+
+    ResolvedField field = 
analysis.getColumnReferenceFields().get(NodeRef.of(expression));
+
+    if (scope.isLocalScope(field.getScope())) {
+      return Optional.of(fieldSymbols[field.getHierarchyFieldIndex()]);
+    }
+
+    if (outerContext.isPresent()) {
+      return Optional.of(Symbol.from(outerContext.get().rewrite(expression)));
+    }
+
+    return Optional.empty();
+  }
+
+  private static void verifyAstExpression(Expression astExpression) {
+    verify(
+        AstUtil.preOrder(astExpression)
+            .noneMatch(expression -> expression instanceof SymbolReference),
+        "symbol references are not allowed");
+  }
+
+  public Scope getScope() {
+    return scope;
+  }
+}
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 8d03eadc6c1..3de51a1b89b 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
@@ -25,9 +25,13 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Cast;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CoalesceExpression;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FieldReference;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InPredicate;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNotNullPredicate;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNullPredicate;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LikePredicate;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NotExpression;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NullIfExpression;
@@ -46,6 +50,16 @@ public class ExpressionRewriter<C> {
     // node.getClass().getName()));
   }
 
+  public Expression rewriteFieldReference(
+      FieldReference node, C context, ExpressionTreeRewriter<C> treeRewriter) {
+    return rewriteExpression(node, context, treeRewriter);
+  }
+
+  public Expression rewriteIdentifier(
+      Identifier node, C context, ExpressionTreeRewriter<C> treeRewriter) {
+    return rewriteExpression(node, context, treeRewriter);
+  }
+
   public Expression rewriteRow(Row node, C context, ExpressionTreeRewriter<C> 
treeRewriter) {
     return rewriteExpression(node, context, treeRewriter);
   }
@@ -80,6 +94,11 @@ public class ExpressionRewriter<C> {
     return rewriteExpression(node, context, treeRewriter);
   }
 
+  public Expression rewriteIsNotNullPredicate(
+      IsNotNullPredicate node, C context, ExpressionTreeRewriter<C> 
treeRewriter) {
+    return rewriteExpression(node, context, treeRewriter);
+  }
+
   public Expression rewriteIsNullPredicate(
       IsNullPredicate node, C context, ExpressionTreeRewriter<C> treeRewriter) 
{
     return rewriteExpression(node, context, treeRewriter);
@@ -114,6 +133,10 @@ public class ExpressionRewriter<C> {
   // ExpressionTreeRewriter<C> treeRewriter) {
   //        return rewriteExpression(node, context, treeRewriter);
   //    }
+  public Expression rewriteLikePredicate(
+      LikePredicate node, C context, ExpressionTreeRewriter<C> treeRewriter) {
+    return rewriteExpression(node, context, treeRewriter);
+  }
 
   public Expression rewriteInPredicate(
       InPredicate node, C context, ExpressionTreeRewriter<C> 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
deleted file mode 100644
index 5ad5448ddd2..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/ir/ExpressionTranslateVisitor.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed 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.queryengine.plan.relational.planner.PlanBuilder;
-import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ArithmeticBinaryExpression;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IfExpression;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InListExpression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InPredicate;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNullPredicate;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LikePredicate;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Literal;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NullIfExpression;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SearchedCaseExpression;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SimpleCaseExpression;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.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 RewritingVisitor<PlanBuilder> {
-
-  private ExpressionTranslateVisitor() {}
-
-  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 visitExpression(Expression node, PlanBuilder context) {
-    throw new IllegalStateException(String.format(NOT_SUPPORTED, 
node.getClass().getName()));
-  }
-
-  @Override
-  protected Expression visitSymbolReference(SymbolReference node, PlanBuilder 
context) {
-    return new 
SymbolReference(context.getSymbolForColumn(node).get().getName());
-  }
-
-  @Override
-  protected Expression visitIdentifier(Identifier node, PlanBuilder context) {
-    return 
context.getSymbolForColumn(node).map(Symbol::toSymbolReference).get();
-  }
-
-  @Override
-  protected Expression visitArithmeticBinary(ArithmeticBinaryExpression node, 
PlanBuilder context) {
-    return new ArithmeticBinaryExpression(
-        node.getOperator(), process(node.getLeft(), context), 
process(node.getRight(), context));
-  }
-
-  @Override
-  protected Expression visitLogicalExpression(LogicalExpression node, 
PlanBuilder context) {
-    return new LogicalExpression(
-        node.getOperator(),
-        node.getTerms().stream().map(e -> process(e, 
context)).collect(toImmutableList()));
-  }
-
-  @Override
-  protected Expression visitLiteral(Literal node, PlanBuilder context) {
-    return node;
-  }
-
-  @Override
-  protected Expression visitComparisonExpression(ComparisonExpression node, 
PlanBuilder context) {
-    Expression left = process(node.getLeft(), context);
-    Expression right = process(node.getRight(), context);
-    return new ComparisonExpression(node.getOperator(), left, right);
-  }
-
-  @Override
-  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 visitIsNullPredicate(IsNullPredicate node, PlanBuilder 
context) {
-    return new IsNullPredicate(process(node.getValue(), context));
-  }
-
-  @Override
-  protected Expression visitInPredicate(InPredicate node, PlanBuilder context) 
{
-    return new InPredicate(
-        process(node.getValue(), context), process(node.getValueList(), 
context));
-  }
-
-  @Override
-  protected Expression visitInListExpression(InListExpression node, 
PlanBuilder context) {
-    List<Expression> newValues =
-        
node.getValues().stream().map(this::process).collect(Collectors.toList());
-    return new InListExpression(newValues);
-  }
-
-  @Override
-  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 visitSimpleCaseExpression(SimpleCaseExpression node, 
PlanBuilder context) {
-    throw new IllegalStateException(String.format(NOT_SUPPORTED, 
node.getClass().getName()));
-  }
-
-  @Override
-  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 f3be5e57c85..7bdfc688126 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
@@ -27,7 +27,9 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InPredicate;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNotNullPredicate;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNullPredicate;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LikePredicate;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Literal;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NotExpression;
@@ -253,6 +255,25 @@ public final class ExpressionTreeRewriter<C> {
       return node;
     }
 
+    @Override
+    protected Expression visitIsNotNullPredicate(IsNotNullPredicate node, 
Context<C> context) {
+      if (!context.isDefaultRewrite()) {
+        Expression result =
+            rewriter.rewriteIsNotNullPredicate(node, context.get(), 
ExpressionTreeRewriter.this);
+        if (result != null) {
+          return result;
+        }
+      }
+
+      Expression value = rewrite(node.getValue(), context.get());
+
+      if (value != node.getValue()) {
+        return new IsNotNullPredicate(value);
+      }
+
+      return node;
+    }
+
     @Override
     protected Expression visitNullIfExpression(NullIfExpression node, 
Context<C> context) {
       if (!context.isDefaultRewrite()) {
@@ -379,6 +400,27 @@ public final class ExpressionTreeRewriter<C> {
       return node;
     }
 
+    @Override
+    public Expression visitLikePredicate(LikePredicate node, Context<C> 
context) {
+      if (!context.isDefaultRewrite()) {
+        Expression result =
+            rewriter.rewriteLikePredicate(node, context.get(), 
ExpressionTreeRewriter.this);
+        if (result != null) {
+          return result;
+        }
+      }
+
+      Expression escape = null;
+      if (node.getEscape().isPresent()) {
+        escape = node.getEscape().get();
+      }
+
+      return new LikePredicate(
+          process(node.getValue(), context),
+          process(node.getPattern(), context),
+          process(escape, context));
+    }
+
     @Override
     public Expression visitInPredicate(InPredicate node, Context<C> context) {
       if (!context.isDefaultRewrite()) {
@@ -449,6 +491,14 @@ public final class ExpressionTreeRewriter<C> {
 
     @Override
     protected Expression visitIdentifier(Identifier node, Context<C> context) {
+      if (!context.isDefaultRewrite()) {
+        Expression result =
+            rewriter.rewriteIdentifier(node, context.get(), 
ExpressionTreeRewriter.this);
+        if (result != null) {
+          return result;
+        }
+      }
+
       return node;
     }
 
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 b32d30f4d05..b0904e877b3 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
@@ -27,6 +27,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ComparisonExpress
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InPredicate;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNotNullPredicate;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.IsNullPredicate;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.NotExpression;
@@ -89,6 +90,10 @@ public abstract class IrVisitor<R, C> extends AstVisitor<R, 
C> {
     return visitExpression(node, context);
   }
 
+  protected R visitIsNotNullPredicate(IsNotNullPredicate node, C context) {
+    return visitExpression(node, context);
+  }
+
   protected R visitIsNullPredicate(IsNullPredicate node, C context) {
     return visitExpression(node, context);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
index 3015f88ce60..5cf01374ef5 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/FilterScanCombine.java
@@ -60,9 +60,10 @@ public class FilterScanCombine implements 
RelationalPlanOptimizer {
       SessionInfo sessionInfo,
       MPPQueryContext queryContext) {
 
-    if (!analysis.hasValueFilter()) {
-      return planNode;
-    }
+    // TODO change back after Gaofei accomplish ScanTimeAndValueFilterSplitRule
+    //    if (!analysis.hasValueFilter()) {
+    //      return planNode;
+    //    }
 
     return planNode.accept(new Rewriter(), new RewriterContext(queryContext));
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LikePredicate.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LikePredicate.java
index ac6caea6c8f..53ab836a94a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LikePredicate.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LikePredicate.java
@@ -42,7 +42,7 @@ public class LikePredicate extends Expression {
     super(null);
     this.value = requireNonNull(value, "value is null");
     this.pattern = requireNonNull(pattern, "pattern is null");
-    this.escape = requireNonNull(escape, "escape is null");
+    this.escape = escape;
   }
 
   public LikePredicate(NodeLocation location, Expression value, Expression 
pattern) {
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 706bba2d0d5..dbd057665ad 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
@@ -204,8 +204,15 @@ public class AnalyzerTest {
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
-    assertTrue(((OutputNode) rootNode).getChild() instanceof TableScanNode);
-    tableScanNode = (TableScanNode) ((OutputNode) rootNode).getChild();
+
+    // TODO change back after Gaofei update FilterAndScanCombineRule
+    /*assertTrue(((OutputNode) rootNode).getChild() instanceof TableScanNode);
+    tableScanNode = (TableScanNode) ((OutputNode) rootNode).getChild();*/
+    assertTrue(((OutputNode) rootNode).getChild() instanceof FilterNode);
+    FilterNode filterNode = (FilterNode) ((OutputNode) rootNode).getChild();
+    assertEquals("(\"time\" > 1)", filterNode.getPredicate().toString());
+
+    tableScanNode = (TableScanNode) (filterNode).getChild();
     assertEquals("table1", tableScanNode.getQualifiedTableName());
     assertEquals(
         Arrays.asList("time", "tag1", "tag2", "tag3", "attr1", "attr2", "s1", 
"s2", "s3"),

Reply via email to