You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ca...@apache.org on 2024/04/16 01:44:02 UTC

(iotdb) 01/05: add optimizer RemoveRedundantIdentityProjections

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

commit 34bf1aa11bb08c976c62f4104a888712e61e2076
Author: Beyyes <cg...@foxmail.com>
AuthorDate: Mon Apr 15 20:13:56 2024 +0800

    add optimizer RemoveRedundantIdentityProjections
---
 .../plan/planner/plan/node/PlanNode.java           |   6 +
 .../plan/planner/plan/node/PlanVisitor.java        |   5 +
 .../plan/relational/planner/Assignments.java       |   5 +-
 .../plan/relational/planner/LogicalPlanner.java    |   7 +-
 .../plan/relational/planner/PlanBuilder.java       |   6 +-
 .../plan/relational/planner/QueryPlanner.java      |  37 ++--
 .../plan/relational/planner/RelationPlan.java      |   6 +-
 .../plan/relational/planner/RelationPlanner.java   | 188 +++++++--------------
 .../plan/relational/planner/node/FilterNode.java   |   8 +-
 .../plan/relational/planner/node/LimitNode.java    |  10 +-
 .../plan/relational/planner/node/OffsetNode.java   |   8 +-
 .../plan/relational/planner/node/OutputNode.java   |  20 ++-
 .../plan/relational/planner/node/ProjectNode.java  |  14 +-
 .../plan/relational/planner/node/SortNode.java     |  12 +-
 .../relational/planner/node/TableScanNode.java     |   5 +
 ...ava => RemoveRedundantIdentityProjections.java} |  60 ++++---
 .../planner/optimizations/SimplifyExpressions.java |   4 -
 .../plan/relational/analyzer/AnalyzerTest.java     |   3 +-
 18 files changed, 207 insertions(+), 197 deletions(-)

diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java
index 877db9bf543..b8a9ebf66f6 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.queryengine.plan.planner.plan.node;
 import org.apache.iotdb.commons.exception.runtime.SerializationRunTimeException;
 import org.apache.iotdb.consensus.common.request.IConsensusRequest;
 import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 import org.apache.iotdb.tsfile.utils.PublicBAOS;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
@@ -206,4 +207,9 @@ public abstract class PlanNode implements IConsensusRequest {
   public int hashCode() {
     return Objects.hash(id);
   }
+
+  // =========================== Used for Relational Model ============================
+  public List<Symbol> getOutputSymbols() {
+    throw new UnsupportedOperationException("This planNode does not support getOutputSymbols().");
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
index 9e893bbc653..393f46a43ba 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
@@ -518,4 +518,9 @@ public abstract class PlanVisitor<R, C> {
   public R visitTableScan(TableScanNode node, C context) {
     return visitPlan(node, context);
   }
+
+  public R visitProject(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode node, C context) {
+    return visitPlan(node, context);
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java
index 992ada2a745..a439f41f00b 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java
@@ -37,6 +37,9 @@ import static java.util.Arrays.asList;
 import static java.util.Objects.requireNonNull;
 
 public class Assignments {
+
+  private final Map<Symbol, Expression> assignments;
+
   public static Builder builder() {
     return new Builder();
   }
@@ -66,8 +69,6 @@ public class Assignments {
     return builder().put(symbol1, expression1).put(symbol2, expression2).build();
   }
 
-  private final Map<Symbol, Expression> assignments;
-
   @JsonCreator
   public Assignments(@JsonProperty("assignments") Map<Symbol, Expression> assignments) {
     this.assignments = ImmutableMap.copyOf(requireNonNull(assignments, "assignments is null"));
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
index f11c0d86f98..5e54848763f 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.analyzer.RelationType;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RelationalPlanOptimizer;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RemoveRedundantIdentityProjections;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.SimplifyExpressions;
 import org.apache.iotdb.db.relational.sql.tree.Query;
 import org.apache.iotdb.db.relational.sql.tree.Statement;
@@ -34,7 +35,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import io.airlift.log.Logger;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import static java.util.Objects.requireNonNull;
@@ -58,8 +59,8 @@ public class LogicalPlanner {
     this.sessionInfo = requireNonNull(sessionInfo, "session is null");
     this.warningCollector = requireNonNull(warningCollector, "warningCollector is null");
 
-    this.relationalPlanOptimizers = new ArrayList<>();
-    this.relationalPlanOptimizers.add(new SimplifyExpressions());
+    this.relationalPlanOptimizers =
+        Arrays.asList(new SimplifyExpressions(), new RemoveRedundantIdentityProjections());
   }
 
   public LogicalQueryPlan plan(Analysis analysis) throws IoTDBException {
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 2045233cb37..a34e17dbf85 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
@@ -29,7 +29,8 @@ import java.util.Map;
 
 import static java.util.Objects.requireNonNull;
 
-class PlanBuilder {
+public class PlanBuilder {
+
   private final PlanNode root;
 
   public PlanBuilder(PlanNode root) {
@@ -68,8 +69,7 @@ class PlanBuilder {
     Assignments.Builder projections = Assignments.builder();
 
     // add an identity projection for underlying plan
-    // TODO needed?
-    // projections.putIdentities(root.getOutputSymbols());
+    projections.putIdentities(root.getOutputSymbols());
 
     Map<ScopeAware<Expression>, Symbol> mappings = new HashMap<>();
     //        for (T expression : expressions) {
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 eb23a4a2cbf..768cd3ca4b5 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
@@ -28,6 +28,7 @@ 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;
 import org.apache.iotdb.db.relational.sql.tree.Query;
+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;
@@ -47,18 +48,17 @@ 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;
 
-class QueryPlanner {
-  private static final int MAX_BIGINT_PRECISION = 19;
+public class QueryPlanner {
   private final Analysis analysis;
   private final SymbolAllocator symbolAllocator;
   private final QueryId idAllocator;
-  // private final Map<NodeRef<LambdaArgumentDeclaration>, Symbol> lambdaDeclarationToSymbolMap;
-  // private final PlannerContext plannerContext;
   private final SessionInfo session;
-  // private final SubqueryPlanner subqueryPlanner;
   private final Map<NodeRef<Node>, RelationPlan> recursiveSubqueries;
 
-  QueryPlanner(
+  // private final Map<NodeRef<LambdaArgumentDeclaration>, Symbol> lambdaDeclarationToSymbolMap;
+  // private final SubqueryPlanner subqueryPlanner;
+
+  public QueryPlanner(
       Analysis analysis,
       SymbolAllocator symbolAllocator,
       QueryId idAllocator,
@@ -74,12 +74,11 @@ class QueryPlanner {
     this.symbolAllocator = symbolAllocator;
     this.idAllocator = idAllocator;
     this.session = session;
-    // this.subqueryPlanner = null;
     this.recursiveSubqueries = recursiveSubqueries;
   }
 
   public RelationPlan plan(Query query) {
-    PlanBuilder builder = planQueryBody(query);
+    PlanBuilder builder = planQueryBody(query.getQueryBody());
 
     List<Expression> orderBy = analysis.getOrderByExpressions(query);
     // builder = subqueryPlanner.handleSubqueries(builder, orderBy, analysis.getSubqueries(query));
@@ -108,20 +107,16 @@ class QueryPlanner {
     PlanBuilder builder = planFrom(node);
 
     builder = filter(builder, analysis.getWhere(node), node);
-    // builder = aggregate(builder, node);
-    builder = filter(builder, analysis.getHaving(node), node);
-    // builder = planWindowFunctions(node, builder,
-    // ImmutableList.copyOf(analysis.getWindowFunctions(node)));
-    // builder = planWindowMeasures(node, builder,
-    // ImmutableList.copyOf(analysis.getWindowMeasures(node)));
+
+    // TODO prcess aggregate, having later
 
     List<Analysis.SelectExpression> selectExpressions = analysis.getSelectExpressions(node);
     List<Expression> expressions =
         selectExpressions.stream()
             .map(Analysis.SelectExpression::getExpression)
             .collect(toImmutableList());
-    // builder = subqueryPlanner.handleSubqueries(builder, expressions,
-    // analysis.getSubqueries(node));
+
+    // TODO process subQuery later
 
     if (hasExpressionsToUnfold(selectExpressions)) {
       // pre-project the folded expressions to preserve any non-deterministic semantics of functions
@@ -160,10 +155,12 @@ class QueryPlanner {
     }
 
     List<Expression> orderBy = analysis.getOrderByExpressions(node);
+    // TODO this appendProjections may be removed
     builder =
         builder.appendProjections(Iterables.concat(orderBy, outputs), symbolAllocator, idAllocator);
 
-    // builder = distinct(builder, node, outputs);
+    // TODO handle distinct
+
     Optional<OrderingScheme> orderingScheme =
         orderingScheme(builder, node.getOrderBy(), analysis.getOrderByExpressions(node));
     builder = sort(builder, orderingScheme);
@@ -208,10 +205,10 @@ class QueryPlanner {
     return outputSymbols.build();
   }
 
-  private PlanBuilder planQueryBody(Query query) {
+  private PlanBuilder planQueryBody(QueryBody queryBody) {
     RelationPlan relationPlan =
         new RelationPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries)
-            .process(query.getQueryBody(), null);
+            .process(queryBody, null);
 
     return newPlanBuilder(relationPlan, analysis, session);
   }
@@ -223,7 +220,7 @@ class QueryPlanner {
               .process(node.getFrom().get(), null);
       return newPlanBuilder(relationPlan, analysis, session);
     } else {
-      throw new RuntimeException("From clause must not by empty");
+      throw new IllegalStateException("From clause must not by empty");
     }
   }
 
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java
index 5ece186d194..cdd1bab217f 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java
@@ -29,15 +29,15 @@ import static java.util.Objects.requireNonNull;
  * values, etc.), and the mapping to indicate how the fields (by position) in the relation map to
  * the outputs of the plan.
  */
-class RelationPlan {
+public class RelationPlan {
 
   private final PlanNode root;
 
+  private final Scope scope;
+
   // for each field in the relation, the corresponding symbol from "root"
   private final List<Symbol> fieldMappings;
 
-  private final Scope scope;
-
   public RelationPlan(PlanNode root, Scope scope, List<Symbol> fieldMappings) {
     requireNonNull(root, "root is null");
     requireNonNull(fieldMappings, "fieldMappings is null");
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 9e180d3dc4c..b42cc50c693 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
@@ -25,11 +25,17 @@ import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 import org.apache.iotdb.db.relational.sql.tree.AliasedRelation;
 import org.apache.iotdb.db.relational.sql.tree.AstVisitor;
+import org.apache.iotdb.db.relational.sql.tree.Except;
+import org.apache.iotdb.db.relational.sql.tree.Intersect;
+import org.apache.iotdb.db.relational.sql.tree.Join;
 import org.apache.iotdb.db.relational.sql.tree.Node;
 import org.apache.iotdb.db.relational.sql.tree.Query;
 import org.apache.iotdb.db.relational.sql.tree.QuerySpecification;
 import org.apache.iotdb.db.relational.sql.tree.SubqueryExpression;
 import org.apache.iotdb.db.relational.sql.tree.Table;
+import org.apache.iotdb.db.relational.sql.tree.TableSubquery;
+import org.apache.iotdb.db.relational.sql.tree.Union;
+import org.apache.iotdb.db.relational.sql.tree.Values;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -40,14 +46,14 @@ import java.util.Map;
 
 import static java.util.Objects.requireNonNull;
 
-class RelationPlanner extends AstVisitor<RelationPlan, Void> {
+public class RelationPlanner extends AstVisitor<RelationPlan, Void> {
   private final Analysis analysis;
   private final SymbolAllocator symbolAllocator;
   private final QueryId idAllocator;
   private final SessionInfo session;
   private final Map<NodeRef<Node>, RelationPlan> recursiveSubqueries;
 
-  RelationPlanner(
+  public RelationPlanner(
       Analysis analysis,
       SymbolAllocator symbolAllocator,
       QueryId idAllocator,
@@ -67,8 +73,9 @@ class RelationPlanner extends AstVisitor<RelationPlan, Void> {
   }
 
   @Override
-  protected RelationPlan visitNode(Node node, Void context) {
-    throw new IllegalStateException("Unsupported node type: " + node.getClass().getName());
+  protected RelationPlan visitQuery(Query node, Void context) {
+    return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries)
+        .plan(node);
   }
 
   @Override
@@ -83,154 +90,81 @@ class RelationPlanner extends AstVisitor<RelationPlan, Void> {
           expansion.getRoot(), expansion.getScope(), expansion.getFieldMappings());
     }
 
-    Query namedQuery = analysis.getNamedQuery(node);
     Scope scope = analysis.getScope(node);
+    TableHandle tableHandle = analysis.getTableHandle(node);
 
-    RelationPlan plan;
-    if (namedQuery != null) {
-      throw new RuntimeException("NamedQuery is not supported");
-    } else {
-      TableHandle handle = analysis.getTableHandle(node);
+    ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder();
+    ImmutableMap.Builder<Symbol, ColumnHandle> columnsBuilder = ImmutableMap.builder();
 
-      ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder();
-      ImmutableMap.Builder<Symbol, ColumnHandle> columns = ImmutableMap.builder();
-
-      // Collection<Field> fields = analysis.getMaterializedViewStorageTableFields(node);
-      Collection<Field> fields = scope.getRelationType().getAllFields();
-      for (Field field : fields) {
-        Symbol symbol = symbolAllocator.newSymbol(field);
+    Collection<Field> fields = scope.getRelationType().getAllFields();
+    for (Field field : fields) {
+      Symbol symbol = symbolAllocator.newSymbol(field);
+      outputSymbolsBuilder.add(symbol);
+      columnsBuilder.put(symbol, analysis.getColumn(field));
+    }
 
-        outputSymbolsBuilder.add(symbol);
-        columns.put(symbol, analysis.getColumn(field));
-      }
+    List<Symbol> outputSymbols = outputSymbolsBuilder.build();
+    PlanNode root =
+        new TableScanNode(
+            idAllocator.genPlanNodeId(), tableHandle, outputSymbols, columnsBuilder.buildOrThrow());
 
-      List<Symbol> outputSymbols = outputSymbolsBuilder.build();
-      PlanNode root =
-          new TableScanNode(
-              idAllocator.genPlanNodeId(), handle, outputSymbols, columns.buildOrThrow());
+    return new RelationPlan(root, scope, outputSymbols);
 
-      plan = new RelationPlan(root, scope, outputSymbols);
-    }
-
-    // TODO what's the meaning of RowFilters addColumnMasks?
+    // Query namedQuery = analysis.getNamedQuery(node);
+    // Collection<Field> fields = analysis.getMaterializedViewStorageTableFields(node);
     // plan = addRowFilters(node, plan);
     // plan = addColumnMasks(node, plan);
-
-    return plan;
   }
 
-  //  private RelationPlan addRowFilters(Table node, RelationPlan plan) {
-  //    return addRowFilters(node, plan, Function.identity());
-  //  }
-
-  //  public RelationPlan addRowFilters(
-  //      Table node, RelationPlan plan, Function<Expression, Expression> predicateTransformation) {
-  //    List<Expression> filters = null;
-  //    // analysis.getRowFilters(node);
-  //
-  //    if (filters.isEmpty()) {
-  //      return plan;
-  //    }
-  //
-  //    // The fields in the access control scope has the same layout as those for the table scope
-  //    PlanBuilder planBuilder = newPlanBuilder(plan, analysis, session);
-  //    // .withScope(accessControlScope.apply(node), plan.getFieldMappings());
-  //
-  //    for (Expression filter : filters) {
-  //      // planBuilder = subqueryPlanner.handleSubqueries(planBuilder, filter,
-  //      // analysis.getSubqueries(filter));
-  //
-  //      Expression predicate = coerceIfNecessary(analysis, filter, filter);
-  //      predicate = predicateTransformation.apply(predicate);
-  //      planBuilder =
-  //          planBuilder.withNewRoot(
-  //              new FilterNode(idAllocator.genPlanNodeId(), planBuilder.getRoot(), predicate));
-  //    }
-  //
-  //    return new RelationPlan(planBuilder.getRoot(), plan.getScope(), plan.getFieldMappings());
-  //  }
-
-  //    private RelationPlan addColumnMasks(Table table, RelationPlan plan) {
-  //        Map<String, Expression> columnMasks = analysis.getColumnMasks(table);
-  //
-  //        // A Table can represent a WITH query, which can have anonymous fields. On the other
-  // hand,
-  //        // it can't have masks. The loop below expects fields to have proper names, so bail out
-  //        // if the masks are missing
-  //        if (columnMasks.isEmpty()) {
-  //            return plan;
-  //        }
-  //
-  //        // The fields in the access control scope has the same layout as those for the table
-  // scope
-  //        PlanBuilder planBuilder = newPlanBuilder(plan, analysis, session)
-  //                .withScope(analysis.getAccessControlScope(table), plan.getFieldMappings());
-  //
-  //        Assignments.Builder assignments = Assignments.builder();
-  //        assignments.putIdentities(planBuilder.getRoot().getOutputSymbols());
-  //
-  //        List<Symbol> fieldMappings = new ArrayList<>();
-  //        for (int i = 0; i < plan.getDescriptor().getAllFieldCount(); i++) {
-  //            Field field = plan.getDescriptor().getFieldByIndex(i);
-  //
-  //            Expression mask = columnMasks.get(field.getName().orElseThrow());
-  //            Symbol symbol = plan.getFieldMappings().get(i);
-  //            Expression projection = symbol.toSymbolReference();
-  //            if (mask != null) {
-  //                symbol = symbolAllocator.newSymbol(symbol);
-  //                projection = coerceIfNecessary(analysis, mask, planBuilder.rewrite(mask));
-  //            }
-  //
-  //            assignments.put(symbol, projection);
-  //            fieldMappings.add(symbol);
-  //        }
-  //
-  //        planBuilder = planBuilder
-  //                .withNewRoot(new ProjectNode(
-  //                        idAllocator.genPlanNodeId(),
-  //                        planBuilder.getRoot(),
-  //                        assignments.build()));
-  //
-  //        return new RelationPlan(planBuilder.getRoot(), plan.getScope(), fieldMappings);
-  //    }
+  @Override
+  protected RelationPlan visitQuerySpecification(QuerySpecification node, Void context) {
+    return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries)
+        .plan(node);
+  }
 
   @Override
-  protected RelationPlan visitAliasedRelation(AliasedRelation node, Void context) {
-    RelationPlan subPlan = process(node.getRelation(), context);
+  protected RelationPlan visitNode(Node node, Void context) {
+    throw new IllegalStateException("Unsupported node type: " + node.getClass().getName());
+  }
 
-    PlanNode root = subPlan.getRoot();
-    List<Symbol> mappings = subPlan.getFieldMappings();
+  // ================================ Implemented later =====================================
+  @Override
+  protected RelationPlan visitTableSubquery(TableSubquery node, Void context) {
+    throw new IllegalStateException("TableSubquery is not supported in current version.");
+  }
 
-    if (node.getColumnNames() != null) {
-      ImmutableList.Builder<Symbol> newMappings = ImmutableList.builder();
+  @Override
+  protected RelationPlan visitValues(Values node, Void context) {
+    throw new IllegalStateException("Values is not supported in current version.");
+  }
 
-      // Adjust the mappings to expose only the columns visible in the scope of the aliased relation
-      for (int i = 0; i < subPlan.getDescriptor().getAllFieldCount(); i++) {
-        if (!subPlan.getDescriptor().getFieldByIndex(i).isHidden()) {
-          newMappings.add(subPlan.getFieldMappings().get(i));
-        }
-      }
+  @Override
+  protected RelationPlan visitSubqueryExpression(SubqueryExpression node, Void context) {
+    throw new IllegalStateException("SubqueryExpression is not supported in current version.");
+  }
 
-      mappings = newMappings.build();
-    }
+  @Override
+  protected RelationPlan visitJoin(Join node, Void context) {
+    throw new IllegalStateException("Join is not supported in current version.");
+  }
 
-    return new RelationPlan(root, analysis.getScope(node), mappings);
+  @Override
+  protected RelationPlan visitAliasedRelation(AliasedRelation node, Void context) {
+    throw new IllegalStateException("AliasedRelation is not supported in current version.");
   }
 
   @Override
-  protected RelationPlan visitQuery(Query node, Void context) {
-    return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries)
-        .plan(node);
+  protected RelationPlan visitIntersect(Intersect node, Void context) {
+    throw new IllegalStateException("Intersect is not supported in current version.");
   }
 
   @Override
-  protected RelationPlan visitQuerySpecification(QuerySpecification node, Void context) {
-    return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries)
-        .plan(node);
+  protected RelationPlan visitUnion(Union node, Void context) {
+    throw new IllegalStateException("Union is not supported in current version.");
   }
 
   @Override
-  protected RelationPlan visitSubqueryExpression(SubqueryExpression node, Void context) {
-    return process(node.getQuery(), context);
+  protected RelationPlan visitExcept(Except node, Void context) {
+    throw new IllegalStateException("Except is not supported in current version.");
   }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java
index 3c49baa4880..68289d5a83d 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 import org.apache.iotdb.db.relational.sql.tree.Expression;
 
 import java.io.DataOutputStream;
@@ -45,7 +46,7 @@ public class FilterNode extends SingleChildProcessNode {
 
   @Override
   public PlanNode clone() {
-    return null;
+    return new FilterNode(id, child, predicate);
   }
 
   @Override
@@ -66,4 +67,9 @@ public class FilterNode extends SingleChildProcessNode {
   public void setPredicate(Expression predicate) {
     this.predicate = predicate;
   }
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return child.getOutputSymbols();
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
index 41b376e04be..17481074932 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
@@ -4,6 +4,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingScheme;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -13,7 +14,7 @@ import java.util.Optional;
 
 public class LimitNode extends SingleChildProcessNode {
   private final long count;
-  // what's the meaning?
+  // TODO what's the meaning?
   private final Optional<OrderingScheme> tiesResolvingScheme;
   // private final boolean partial;
   // private final List<Symbol> preSortedInputs;
@@ -27,7 +28,7 @@ public class LimitNode extends SingleChildProcessNode {
 
   @Override
   public PlanNode clone() {
-    return null;
+    return new LimitNode(id, child, count, tiesResolvingScheme);
   }
 
   @Override
@@ -40,4 +41,9 @@ public class LimitNode extends SingleChildProcessNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return child.getOutputSymbols();
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
index c4ea93a27cb..69ac2517e83 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
@@ -3,6 +3,7 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.node;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -19,7 +20,7 @@ public class OffsetNode extends SingleChildProcessNode {
 
   @Override
   public PlanNode clone() {
-    return null;
+    return new OffsetNode(id, child, count);
   }
 
   @Override
@@ -32,4 +33,9 @@ public class OffsetNode extends SingleChildProcessNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return child.getOutputSymbols();
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java
index cb884b09a56..514a7bce382 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java
@@ -5,6 +5,8 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 
+import com.google.common.collect.ImmutableList;
+
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -12,22 +14,22 @@ import java.util.List;
 
 public class OutputNode extends SingleChildProcessNode {
 
-  private final List<String> outputColumnNames;
+  private final List<String> columnNames;
 
-  private final List<Symbol> symbols;
+  // column name = symbol
+  private final List<Symbol> outputs;
 
-  public OutputNode(
-      PlanNodeId id, PlanNode child, List<String> outputColumnNames, List<Symbol> symbols) {
+  public OutputNode(PlanNodeId id, PlanNode child, List<String> columnNames, List<Symbol> outputs) {
     super(id, child);
     this.id = id;
     this.child = child;
-    this.outputColumnNames = outputColumnNames;
-    this.symbols = symbols;
+    this.columnNames = ImmutableList.copyOf(columnNames);
+    this.outputs = ImmutableList.copyOf(outputs);
   }
 
   @Override
   public PlanNode clone() {
-    return null;
+    return new OutputNode(id, child, columnNames, outputs);
   }
 
   @Override
@@ -40,4 +42,8 @@ public class OutputNode extends SingleChildProcessNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  public List<Symbol> getOutputSymbols() {
+    return outputs;
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java
index ff8de50de27..ed65602cf9e 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java
@@ -2,8 +2,10 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.node;
 
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.Assignments;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -18,9 +20,14 @@ public class ProjectNode extends SingleChildProcessNode {
     this.assignments = assignments;
   }
 
+  @Override
+  public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+    return visitor.visitProject(this, context);
+  }
+
   @Override
   public PlanNode clone() {
-    return null;
+    return new ProjectNode(id, child, assignments);
   }
 
   @Override
@@ -33,4 +40,9 @@ public class ProjectNode extends SingleChildProcessNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return assignments.getOutputs();
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java
index 37358d3d696..2ea9f7081c2 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java
@@ -4,6 +4,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingScheme;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -14,15 +15,15 @@ public class SortNode extends SingleChildProcessNode {
   private final OrderingScheme orderingScheme;
   private final boolean partial;
 
-  public SortNode(PlanNodeId id, PlanNode planNode, OrderingScheme scheme, boolean partial) {
-    super(id, planNode);
+  public SortNode(PlanNodeId id, PlanNode child, OrderingScheme scheme, boolean partial) {
+    super(id, child);
     this.orderingScheme = scheme;
     this.partial = partial;
   }
 
   @Override
   public PlanNode clone() {
-    return null;
+    return new SortNode(id, child, orderingScheme, partial);
   }
 
   @Override
@@ -35,4 +36,9 @@ public class SortNode extends SingleChildProcessNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return child.getOutputSymbols();
+  }
 }
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 1b7c2476ba3..68eb557a38b 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
@@ -62,4 +62,9 @@ public class TableScanNode extends PlanNode {
 
   @Override
   protected void serializeAttributes(DataOutputStream stream) throws IOException {}
+
+  @Override
+  public List<Symbol> getOutputSymbols() {
+    return outputSymbols;
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
similarity index 52%
copy from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java
copy to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
index aef419fa123..d7366dfe9df 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
@@ -17,42 +17,52 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 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.planner.plan.node.PlanVisitor;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
-import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
-import org.apache.iotdb.db.relational.sql.tree.Expression;
 
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExtractCommonPredicatesExpressionRewriter.extractCommonPredicates;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.NormalizeOrExpressionRewriter.normalizeOrExpression;
+import java.util.Collections;
+import java.util.List;
 
-public class SimplifyExpressions implements RelationalPlanOptimizer {
+public class RemoveRedundantIdentityProjections implements RelationalPlanOptimizer {
 
   @Override
   public PlanNode optimize(PlanNode planNode, Analysis analysis, MPPQueryContext context) {
-    // TODO add query statement pruning
     return planNode.accept(new Rewriter(), new RewriterContext());
   }
 
   private static class Rewriter extends PlanVisitor<PlanNode, RewriterContext> {
-
     @Override
     public PlanNode visitPlan(PlanNode node, RewriterContext context) {
-      // PlanNode newNode = node.clone();
-      if (node.getChildren() == null) {
-        System.out.println("aa");
-      }
+      PlanNode newNode = node.clone();
       for (PlanNode child : node.getChildren()) {
-        child.accept(this, context);
+        context.setParent(node);
+        newNode.addChild(child.accept(this, context));
       }
-      return node;
+      return newNode;
     }
 
     @Override
-    public PlanNode visitFilter(FilterNode node, RewriterContext context) {
-      Expression predicate = normalizeOrExpression(node.getPredicate());
-      predicate = extractCommonPredicates(predicate);
-      node.setPredicate(predicate);
-      return node;
+    public PlanNode visitProject(ProjectNode projectNode, RewriterContext context) {
+      if (projectNode.getOutputSymbols().equals(projectNode.getChild().getOutputSymbols())) {
+        if (context.getParent() instanceof SingleChildProcessNode) {
+          ((SingleChildProcessNode) context.getParent()).setChild(projectNode.getChild());
+        } else {
+          List<PlanNode> children = context.getParent().getChildren();
+          for (int i = 0; i < children.size(); i++) {
+            PlanNode child = children.get(i);
+            if (child.getPlanNodeId().equals(projectNode.getPlanNodeId())) {
+              Collections.swap(children, i, children.size() - 1);
+              children.remove(children.size() - 1);
+              break;
+            }
+          }
+        }
+        return projectNode.getChild();
+      } else {
+        return projectNode;
+      }
     }
 
     @Override
@@ -61,5 +71,17 @@ public class SimplifyExpressions implements RelationalPlanOptimizer {
     }
   }
 
-  private static class RewriterContext {}
+  private static class RewriterContext {
+    private PlanNode parent;
+
+    public RewriterContext() {}
+
+    public PlanNode getParent() {
+      return this.parent;
+    }
+
+    public void setParent(PlanNode parent) {
+      this.parent = parent;
+    }
+  }
 }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java
index aef419fa123..1e5839fe32a 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java
@@ -37,10 +37,6 @@ public class SimplifyExpressions implements RelationalPlanOptimizer {
 
     @Override
     public PlanNode visitPlan(PlanNode node, RewriterContext context) {
-      // PlanNode newNode = node.clone();
-      if (node.getChildren() == null) {
-        System.out.println("aa");
-      }
       for (PlanNode child : node.getChildren()) {
         child.accept(this, context);
       }
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 c42342c16cd..143bd906fbe 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
@@ -134,9 +134,10 @@ public class AnalyzerTest {
 
   @Test
   public void testSingleTableQuery() throws IoTDBException {
+    // no sort
     String sql =
         "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 "
-            + "WHERE time>1 AND tag1='A' OR s2>3 ORDER BY time DESC OFFSET 10 LIMIT 5";
+            + "WHERE time>1 AND tag1='A' OR s2>3 OFFSET 10 LIMIT 5";
     Metadata metadata = new TestMatadata();
 
     Analysis actualAnalysis = analyzeSQL(sql, metadata);