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 3e8bbf11e87 Put method getDataPartition into class Metadata, add basic 
sort implementation
3e8bbf11e87 is described below

commit 3e8bbf11e87cf3dcbe19f7e93976bd37e758fe75
Author: Beyyes <[email protected]>
AuthorDate: Mon Jun 24 12:21:06 2024 +0800

    Put method getDataPartition into class Metadata, add basic sort 
implementation
---
 .../TableModelStatementMemorySourceVisitor.java    |   2 -
 .../plan/planner/plan/node/PlanGraphPrinter.java   |  41 ++++
 .../plan/planner/plan/node/PlanVisitor.java        |  23 +-
 .../plan/relational/metadata/Metadata.java         |   3 +
 .../relational/metadata/TableMetadataImpl.java     |   5 +
 .../plan/relational/planner/LogicalPlanner.java    |   8 +-
 .../plan/relational/planner/OrderingScheme.java    |   2 +-
 .../plan/relational/planner/PlanBuilder.java       |   4 +
 .../plan/relational/planner/QueryPlanner.java      |   9 +-
 .../relational/planner/RelationalModelPlanner.java |   8 +-
 .../TableModelTypeProviderExtractor.java           |  37 ++-
 .../planner/optimizations/FilterScanCombine.java   |   2 -
 .../planner/optimizations/IndexScan.java           |  13 +-
 .../planner/optimizations/PruneUnUsedColumns.java  |  10 +-
 .../optimizations/RelationalPlanOptimizer.java     |   2 -
 .../RemoveRedundantIdentityProjections.java        |   5 +-
 .../planner/optimizations/SimplifyExpressions.java |   2 -
 .../plan/relational/analyzer/AnalyzerTest.java     | 250 ++++++++-------------
 .../plan/relational/analyzer/TestMatadata.java     |  87 +++++++
 19 files changed, 290 insertions(+), 223 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
index 3fade63011d..d0a90a7ede3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
@@ -23,7 +23,6 @@ import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
 import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
 import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
-import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.planner.LocalExecutionPlanner;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanGraphPrinter;
@@ -67,7 +66,6 @@ public class TableModelStatementMemorySourceVisitor
                 context.getQueryContext(),
                 LocalExecutionPlanner.getInstance().metadata,
                 context.getQueryContext().getSession(),
-                ClusterPartitionFetcher.getInstance(),
                 WarningCollector.NOOP)
             .plan(context.getAnalysis());
     if (context.getAnalysis().getDataPartition() == null
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
index 380a7f60cbc..7f94c4ba316 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
@@ -652,6 +652,47 @@ public class PlanGraphPrinter extends 
PlanVisitor<List<String>, PlanGraphPrinter
     return render(node, boxValue, context);
   }
 
+  @Override
+  public List<String> visitLimit(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.LimitNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Limit-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("Count: %s", node.getCount()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitOffset(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Offset-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("Count: %s", node.getCount()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitSort(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Sort-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("OrderingScheme: %s", 
node.getOrderingScheme()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitMergeSort(
+      
org.apache.iotdb.db.queryengine.plan.relational.planner.node.MergeSortNode node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("MergeSort-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("OutputSymbols: %s", node.getOutputSymbols()));
+    boxValue.add(String.format("OrderingScheme: %s", 
node.getOrderingScheme()));
+    return render(node, boxValue, context);
+  }
+
   private String printRegion(TRegionReplicaSet regionReplicaSet) {
     return String.format(
         "Partition: %s",
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 c8ae679b97b..cfd760bb7ba 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
@@ -76,6 +76,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.GroupByTag
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.HorizontallyConcatNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.IntoNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.LimitNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.MergeSortNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.MultiChildProcessNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.OffsetNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ProjectNode;
@@ -116,7 +117,6 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsNo
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsOfOneDeviceNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertTabletNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.CreateTableDeviceNode;
-import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.MergeSortNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 
 @SuppressWarnings("java:S6539") // suppress "Monster class" warning
@@ -312,9 +312,7 @@ public abstract class PlanVisitor<R, C> {
     return visitSingleChildProcess(node, context);
   }
 
-  public R visitMergeSort(
-      
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.MergeSortNode 
node,
-      C context) {
+  public R visitMergeSort(MergeSortNode node, C context) {
     return visitMultiChildProcess(node, context);
   }
 
@@ -556,7 +554,7 @@ public abstract class PlanVisitor<R, C> {
     return visitPlan(node, context);
   }
 
-  // =============================== Used for Relation Model 
====================================
+  // =============================== Used for Table Model 
====================================
   public R visitFilter(
       org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode 
node, C context) {
     return visitSingleChildProcess(node, context);
@@ -573,16 +571,17 @@ public abstract class PlanVisitor<R, C> {
 
   public R visitLimit(
       org.apache.iotdb.db.queryengine.plan.relational.planner.node.LimitNode 
node, C context) {
-    return visitPlan(node, context);
+    return visitSingleChildProcess(node, context);
   }
 
   public R visitOffset(
       org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode 
node, C context) {
-    return visitPlan(node, context);
+    return visitSingleChildProcess(node, context);
   }
 
-  public R visitMergeSort(MergeSortNode node, C context) {
-    return visitPlan(node, context);
+  public R visitMergeSort(
+      
org.apache.iotdb.db.queryengine.plan.relational.planner.node.MergeSortNode 
node, C context) {
+    return visitMultiChildProcess(node, context);
   }
 
   public R visitOutput(
@@ -592,16 +591,16 @@ public abstract class PlanVisitor<R, C> {
 
   public R visitSort(
       org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode 
node, C context) {
-    return visitPlan(node, context);
+    return visitSingleChildProcess(node, context);
   }
 
   public R visitStreamSort(
       
org.apache.iotdb.db.queryengine.plan.relational.planner.node.StreamSortNode 
node, C context) {
-    return visitPlan(node, context);
+    return visitSingleChildProcess(node, context);
   }
 
   public R visitTopK(
       org.apache.iotdb.db.queryengine.plan.relational.planner.node.TopKNode 
node, C context) {
-    return visitPlan(node, context);
+    return visitMultiChildProcess(node, context);
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java
index b369347bdff..8e7fddf677d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java
@@ -22,6 +22,7 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.metadata;
 import org.apache.iotdb.commons.partition.SchemaPartition;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
+import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
@@ -58,6 +59,8 @@ public interface Metadata {
 
   boolean canCoerce(Type from, Type to);
 
+  IPartitionFetcher getPartitionFetcher();
+
   /**
    * get all device ids and corresponding attributes from schema region
    *
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
index 4332c293092..dcf64372cfa 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
@@ -289,6 +289,11 @@ public class TableMetadataImpl implements Metadata {
     return true;
   }
 
+  @Override
+  public IPartitionFetcher getPartitionFetcher() {
+    return ClusterPartitionFetcher.getInstance();
+  }
+
   @Override
   public List<DeviceEntry> indexScan(
       QualifiedObjectName tableName,
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 6e90f59787f..7758a6437f9 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
@@ -22,7 +22,6 @@ import org.apache.iotdb.db.queryengine.common.SessionInfo;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
 import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
 import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
@@ -72,19 +71,16 @@ public class LogicalPlanner {
   private final SymbolAllocator symbolAllocator = new SymbolAllocator();
   private final List<RelationalPlanOptimizer> relationalPlanOptimizers;
   private final Metadata metadata;
-  private final IPartitionFetcher partitionFetcher;
   private final WarningCollector warningCollector;
 
   public LogicalPlanner(
       MPPQueryContext context,
       Metadata metadata,
       SessionInfo sessionInfo,
-      IPartitionFetcher partitionFetcher,
       WarningCollector warningCollector) {
     this.context = context;
     this.metadata = metadata;
     this.sessionInfo = requireNonNull(sessionInfo, "session is null");
-    this.partitionFetcher = requireNonNull(partitionFetcher, "partitionFetcher 
is null");
     this.warningCollector = requireNonNull(warningCollector, "warningCollector 
is null");
 
     this.relationalPlanOptimizers =
@@ -100,9 +96,7 @@ public class LogicalPlanner {
     PlanNode planNode = planStatement(analysis, analysis.getStatement());
 
     relationalPlanOptimizers.forEach(
-        optimizer ->
-            optimizer.optimize(
-                planNode, analysis, metadata, partitionFetcher, sessionInfo, 
context));
+        optimizer -> optimizer.optimize(planNode, analysis, metadata, 
sessionInfo, context));
 
     return new LogicalQueryPlan(context, planNode);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/OrderingScheme.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/OrderingScheme.java
index 9edc2ad3c54..e306538a624 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/OrderingScheme.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/OrderingScheme.java
@@ -127,6 +127,6 @@ public class OrderingScheme {
 
   @Override
   public String toString() {
-    return toStringHelper(this).add("orderBy", orderBy).add("orderings", 
orderings).toString();
+    return toStringHelper("").add("orderBy", orderBy).add("orderings", 
orderings).toString();
   }
 }
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 c4dee45822c..201fa6c4d03 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
@@ -133,6 +133,10 @@ public class PlanBuilder {
       }
     }
 
+    if (mappings.isEmpty()) {
+      return this;
+    }
+
     return new PlanBuilder(
         new ProjectNode(queryContext.getQueryId().genPlanNodeId(), this.root, 
projections.build()),
         this.analysis,
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 cc8ff98032a..0c24f3a3faf 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
@@ -41,7 +41,6 @@ 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;
@@ -147,24 +146,24 @@ public class QueryPlanner {
       // 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);
 
       // 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<>();
+      // List<Symbol> newFields = new ArrayList<>();
       // newFields.addAll(builder.getTranslations().getFieldSymbols());
 
       //            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);
-    // TODO this appendProjections may be removed
-    if (orderBy.size() > 0) {
+    if (!orderBy.isEmpty()) {
       builder =
           builder.appendProjections(
               Iterables.concat(orderBy, outputs), analysis, symbolAllocator, 
queryContext);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
index 60189c42f63..106abe0fd41 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
@@ -27,7 +27,6 @@ import 
org.apache.iotdb.commons.client.sync.SyncDataNodeInternalServiceClient;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.execution.QueryStateMachine;
 import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
-import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.analyze.IAnalysis;
 import org.apache.iotdb.db.queryengine.plan.planner.IPlanner;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.DistributedQueryPlan;
@@ -107,12 +106,7 @@ public class RelationalModelPlanner implements IPlanner {
 
   @Override
   public LogicalQueryPlan doLogicalPlan(IAnalysis analysis, MPPQueryContext 
context) {
-    return new LogicalPlanner(
-            context,
-            metadata,
-            context.getSession(),
-            ClusterPartitionFetcher.getInstance(),
-            warningCollector)
+    return new LogicalPlanner(context, metadata, context.getSession(), 
warningCollector)
         .plan((Analysis) analysis);
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
index 6364d215443..ff73c8c7715 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
@@ -21,9 +21,12 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ExchangeNo
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.sink.IdentitySinkNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 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.MergeSortNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 
@@ -57,14 +60,16 @@ public class TableModelTypeProviderExtractor {
 
     @Override
     public Void visitPlan(PlanNode node, Void context) {
-      node.getOutputSymbols()
-          .forEach(
-              symbol ->
-                  beTypeProvider.putTableModelType(
-                      symbol, feTypeProvider.getTableModelType(symbol)));
-      for (PlanNode source : node.getChildren()) {
-        source.accept(this, context);
+      for (Symbol symbol : node.getOutputSymbols()) {
+        if (!feTypeProvider.isSymbolExist(symbol)) {
+          throw new IllegalStateException(
+              String.format(
+                  "Symbol: %s is not exist in feTypeProvider with %s",
+                  symbol, node.getClass().getSimpleName()));
+        }
+        beTypeProvider.putTableModelType(symbol, 
feTypeProvider.getTableModelType(symbol));
       }
+      node.getChildren().forEach(child -> child.accept(this, context));
       return null;
     }
 
@@ -101,12 +106,30 @@ public class TableModelTypeProviderExtractor {
       return null;
     }
 
+    @Override
+    public Void visitSort(SortNode node, Void context) {
+      node.getChild().accept(this, context);
+      return null;
+    }
+
     @Override
     public Void visitMergeSort(MergeSortNode node, Void context) {
       node.getChildren().forEach(c -> c.accept(this, context));
       return null;
     }
 
+    @Override
+    public Void visitLimit(LimitNode node, Void context) {
+      node.getChild().accept(this, context);
+      return null;
+    }
+
+    @Override
+    public Void visitOffset(OffsetNode node, Void context) {
+      node.getChild().accept(this, context);
+      return null;
+    }
+
     @Override
     public Void visitExchange(ExchangeNode node, Void context) {
       node.getChildren().forEach(c -> c.accept(this, 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 893f3b96617..3015f88ce60 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
@@ -16,7 +16,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 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.MultiChildProcessNode;
@@ -58,7 +57,6 @@ public class FilterScanCombine implements 
RelationalPlanOptimizer {
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext queryContext) {
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
index df986c5ac6b..ab337c3c30f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
@@ -60,13 +60,11 @@ public class IndexScan implements RelationalPlanOptimizer {
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext queryContext) {
 
     return planNode.accept(
-        new Rewriter(),
-        new RewriterContext(null, metadata, sessionInfo, analysis, 
partitionFetcher, queryContext));
+        new Rewriter(), new RewriterContext(null, metadata, sessionInfo, 
analysis, queryContext));
   }
 
   private static class Rewriter extends PlanVisitor<PlanNode, RewriterContext> 
{
@@ -124,7 +122,7 @@ public class IndexScan implements RelationalPlanOptimizer {
                 deviceEntries,
                 treeModelDatabase,
                 context.getQueryContext().getGlobalTimeFilter(),
-                context.getPartitionFetcher(),
+                context.getMetadata().getPartitionFetcher(),
                 context.getQueryContext());
         context.getAnalysis().setDataPartition(dataPartition);
 
@@ -194,7 +192,6 @@ public class IndexScan implements RelationalPlanOptimizer {
     private Metadata metadata;
     private final SessionInfo sessionInfo;
     private final Analysis analysis;
-    private final IPartitionFetcher partitionFetcher;
     private final MPPQueryContext queryContext;
     private FilterNode filterNode;
 
@@ -203,13 +200,11 @@ public class IndexScan implements RelationalPlanOptimizer 
{
         Metadata metadata,
         SessionInfo sessionInfo,
         Analysis analysis,
-        IPartitionFetcher partitionFetcher,
         MPPQueryContext queryContext) {
       this.predicate = predicate;
       this.metadata = metadata;
       this.sessionInfo = sessionInfo;
       this.analysis = analysis;
-      this.partitionFetcher = partitionFetcher;
       this.queryContext = queryContext;
     }
 
@@ -237,10 +232,6 @@ public class IndexScan implements RelationalPlanOptimizer {
       return this.analysis;
     }
 
-    public IPartitionFetcher getPartitionFetcher() {
-      return partitionFetcher;
-    }
-
     public MPPQueryContext getQueryContext() {
       return queryContext;
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
index db9fb4eaa86..8b1ce55f7ae 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PruneUnUsedColumns.java
@@ -17,7 +17,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 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.relational.analyzer.Analysis;
@@ -27,6 +26,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.node.SortNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DefaultTraversalVisitor;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
@@ -57,7 +57,6 @@ public class PruneUnUsedColumns implements 
RelationalPlanOptimizer {
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext context) {
     return planNode.accept(new Rewriter(), new RewriterContext());
@@ -80,6 +79,13 @@ public class PruneUnUsedColumns implements 
RelationalPlanOptimizer {
       return node;
     }
 
+    @Override
+    public PlanNode visitSort(SortNode node, RewriterContext context) {
+      context.allUsedSymbolSet.addAll(node.getOutputSymbols());
+      node.getChild().accept(this, context);
+      return node;
+    }
+
     @Override
     public PlanNode visitProject(ProjectNode node, RewriterContext context) {
       // There must exist OutputNode above ProjectNode
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RelationalPlanOptimizer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RelationalPlanOptimizer.java
index 0e96f27be60..37611e6a35c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RelationalPlanOptimizer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RelationalPlanOptimizer.java
@@ -16,7 +16,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 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.metadata.Metadata;
@@ -26,7 +25,6 @@ public interface RelationalPlanOptimizer {
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext context);
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
index 474a327292f..dcc1e68368e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java
@@ -16,7 +16,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 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;
@@ -35,7 +34,6 @@ public class RemoveRedundantIdentityProjections implements 
RelationalPlanOptimiz
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext context) {
     return planNode.accept(new Rewriter(), new RewriterContext());
@@ -56,7 +54,8 @@ public class RemoveRedundantIdentityProjections implements 
RelationalPlanOptimiz
     @Override
     public PlanNode visitProject(ProjectNode projectNode, RewriterContext 
context) {
       // TODO change the impl using the method of context.getParent()
-      if 
(projectNode.getOutputSymbols().equals(projectNode.getChild().getOutputSymbols()))
 {
+      if (projectNode.getChild() instanceof ProjectNode
+          && 
projectNode.getOutputSymbols().equals(projectNode.getChild().getOutputSymbols()))
 {
         if (context.getParent() instanceof SingleChildProcessNode) {
           ((SingleChildProcessNode) 
context.getParent()).setChild(projectNode.getChild());
         } else {
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 afff2eb2e35..7d308c2cf10 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
@@ -16,7 +16,6 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations;
 
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 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.relational.analyzer.Analysis;
@@ -35,7 +34,6 @@ public class SimplifyExpressions implements 
RelationalPlanOptimizer {
       PlanNode planNode,
       Analysis analysis,
       Metadata metadata,
-      IPartitionFetcher partitionFetcher,
       SessionInfo sessionInfo,
       MPPQueryContext context) {
     // TODO add query statement pruning
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 335d838587e..706bba2d0d5 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
@@ -20,18 +20,11 @@
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 
 import org.apache.iotdb.commons.conf.IoTDBConstant;
-import org.apache.iotdb.commons.exception.IoTDBException;
-import org.apache.iotdb.commons.partition.DataPartition;
-import org.apache.iotdb.commons.partition.DataPartitionQueryParam;
-import org.apache.iotdb.commons.partition.SchemaNodeManagementPartition;
-import org.apache.iotdb.commons.partition.SchemaPartition;
-import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.QueryId;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
 import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
-import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.DistributedQueryPlan;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
@@ -46,6 +39,8 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.LogicalPlanner;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute.TableDistributionPlanner;
 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;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
@@ -53,9 +48,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LogicalExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
-import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
 
-import org.apache.tsfile.file.metadata.IDeviceID;
 import org.junit.Test;
 import org.mockito.Mockito;
 
@@ -170,7 +163,7 @@ public class AnalyzerTest {
   }
 
   @Test
-  public void singleTableNoFilterTest() throws IoTDBException {
+  public void singleTableNoFilterTest() {
     // wildcard
     sql = "SELECT * FROM table1";
     actualAnalysis = analyzeSQL(sql, metadata);
@@ -178,9 +171,7 @@ public class AnalyzerTest {
     assertEquals(1, actualAnalysis.getTables().size());
 
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
@@ -202,16 +193,14 @@ public class AnalyzerTest {
   }
 
   @Test
-  public void singleTableWithFilterTest() throws IoTDBException {
+  public void singleTableWithFilterTest() {
     // global time filter
     sql = "SELECT * FROM table1 where time > 1";
     actualAnalysis = analyzeSQL(sql, metadata);
     assertNotNull(actualAnalysis);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
@@ -235,15 +224,12 @@ public class AnalyzerTest {
     assertNotNull(actualAnalysis);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
-    assertTrue(rootNode.getChildren().get(0) instanceof ProjectNode);
-    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
TableScanNode);
-    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode.getChildren().get(0) instanceof TableScanNode);
+    tableScanNode = (TableScanNode) rootNode.getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag1", "attr1", "s1", "s2"), 
tableScanNode.getOutputColumnNames());
 
@@ -252,19 +238,13 @@ public class AnalyzerTest {
     actualAnalysis = analyzeSQL(sql, metadata);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
-    assertTrue(rootNode.getChildren().get(0) instanceof ProjectNode);
-    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
FilterNode);
-    assertTrue(
-        rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0)
-            instanceof TableScanNode);
-    tableScanNode =
-        (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode.getChildren().get(0) instanceof FilterNode);
+    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
TableScanNode);
+    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag1", "attr1", "s1", "s2"), 
tableScanNode.getOutputColumnNames());
 
@@ -272,37 +252,31 @@ public class AnalyzerTest {
     actualAnalysis = analyzeSQL(sql, metadata);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
-    assertTrue(rootNode.getChildren().get(0) instanceof ProjectNode);
-    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
FilterNode);
-    assertTrue(
-        rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0)
-            instanceof TableScanNode);
-    tableScanNode =
-        (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode.getChildren().get(0) instanceof FilterNode);
+    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
TableScanNode);
+    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag1", "attr1", "s1", "s2"), 
tableScanNode.getOutputColumnNames());
   }
 
   @Test
-  public void singleTableProjectTest() throws IoTDBException {
+  public void singleTableProjectTest() {
     // 1. project without filter
     sql = "SELECT tag1, attr1, s1 FROM table1";
     actualAnalysis = analyzeSQL(sql, metadata);
     assertNotNull(actualAnalysis);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
-    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode instanceof OutputNode);
+    assertTrue(rootNode.getChildren().get(0) instanceof TableScanNode);
+    tableScanNode = (TableScanNode) rootNode.getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag1", "attr1", "s1"), 
tableScanNode.getOutputColumnNames());
 
@@ -312,12 +286,12 @@ public class AnalyzerTest {
     assertNotNull(actualAnalysis);
     assertEquals(1, actualAnalysis.getTables().size());
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
-    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode instanceof OutputNode);
+    assertTrue(rootNode.getChildren().get(0) instanceof TableScanNode);
+    tableScanNode = (TableScanNode) rootNode.getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag1", "tag2", "attr1", "s1", "s2"),
         tableScanNode.getOutputColumnNames());
@@ -328,8 +302,7 @@ public class AnalyzerTest {
     actualAnalysis = analyzeSQL(sql, metadata);
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
FilterNode);
@@ -344,25 +317,25 @@ public class AnalyzerTest {
     actualAnalysis = analyzeSQL(sql, metadata);
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
-    tableScanNode = (TableScanNode) 
rootNode.getChildren().get(0).getChildren().get(0);
+    assertTrue(rootNode instanceof OutputNode);
+    assertTrue(rootNode.getChildren().get(0) instanceof TableScanNode);
+    tableScanNode = (TableScanNode) rootNode.getChildren().get(0);
     assertEquals(
         Arrays.asList("time", "tag2", "attr2", "s2"), 
tableScanNode.getOutputColumnNames());
     assertEquals(2, tableScanNode.getIdAndAttributeIndexMap().size());
   }
 
   @Test
-  public void expressionTest() throws IoTDBException {
+  public void expressionTest() {
     // 1. is null / is not null
     sql = "SELECT * FROM table1 WHERE tag1 is not null and s1 is null";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -371,8 +344,7 @@ public class AnalyzerTest {
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -382,8 +354,7 @@ public class AnalyzerTest {
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -392,21 +363,18 @@ public class AnalyzerTest {
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
   }
 
   @Test
-  public void functionTest() throws IoTDBException {
+  public void functionTest() {
     // 1. cast
     sql = "SELECT CAST(s2 AS DOUBLE) FROM table1 WHERE CAST(s1 AS DOUBLE) > 
1.0";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -415,9 +383,7 @@ public class AnalyzerTest {
         "SELECT SUBSTRING(tag1, 2), SUBSTRING(tag2, s1) FROM table1 WHERE 
SUBSTRING(tag2, 1) = 'A'";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -425,9 +391,7 @@ public class AnalyzerTest {
     sql = "SELECT ROUND(s1, 1) FROM table1 WHERE ROUND(s2, 2) > 1.0";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -435,9 +399,7 @@ public class AnalyzerTest {
     sql = "SELECT REPLACE(tag1, 'A', 'B') FROM table1 WHERE REPLACE(attr1, 
'C', 'D') = 'D'";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
 
@@ -445,15 +407,13 @@ public class AnalyzerTest {
     sql = "SELECT DIFF(s1) FROM table1 WHERE DIFF(s2) > 0";
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
-    logicalPlanner =
-        new LogicalPlanner(
-            context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP);
+    logicalPlanner = new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP);
     logicalQueryPlan = logicalPlanner.plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
   }
 
   @Test
-  public void predicatePushDownTest() throws IoTDBException {
+  public void predicatePushDownTest() {
     // `is null expression`, `not expression` cannot be pushed down into 
TableScanOperator
     sql =
         "SELECT *, s1/2, s2+1 FROM table1 WHERE tag1 in ('A', 'B') and tag2 = 
'C' "
@@ -461,8 +421,7 @@ public class AnalyzerTest {
     context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
     actualAnalysis = analyzeSQL(sql, metadata);
     logicalQueryPlan =
-        new LogicalPlanner(
-                context, metadata, sessionInfo, getFakePartitionFetcher(), 
WarningCollector.NOOP)
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
             .plan(actualAnalysis);
     rootNode = logicalQueryPlan.getRootNode();
     assertTrue(rootNode instanceof OutputNode);
@@ -482,6 +441,52 @@ public class AnalyzerTest {
     assertEquals(2, ((LogicalExpression) 
tableScanNode.getPushDownPredicate()).getTerms().size());
   }
 
+  @Test
+  public void limitOffsetTest() {
+    sql = "SELECT tag1, attr1, s1 FROM table1 offset 3 limit 5";
+    context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
+    actualAnalysis = analyzeSQL(sql, metadata);
+    logicalQueryPlan =
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
+            .plan(actualAnalysis);
+    rootNode = logicalQueryPlan.getRootNode();
+    assertTrue(rootNode.getChildren().get(0) instanceof LimitNode);
+    LimitNode limitNode = (LimitNode) rootNode.getChildren().get(0);
+    assertEquals(5, limitNode.getCount());
+    OffsetNode offsetNode = (OffsetNode) limitNode.getChild();
+    assertEquals(3, offsetNode.getCount());
+
+    sql =
+        "SELECT *, s1/2, s2+1 FROM table1 WHERE tag1 in ('A', 'B') and tag2 = 
'C' "
+            + "and s2 iS NUll and S1 = 6 and s3 < 8.0 and tAG1 LIKE '%m' 
offset 3 limit 5";
+    context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
+    actualAnalysis = analyzeSQL(sql, metadata);
+    logicalQueryPlan =
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
+            .plan(actualAnalysis);
+    rootNode = logicalQueryPlan.getRootNode();
+    assertTrue(rootNode.getChildren().get(0) instanceof ProjectNode);
+    assertTrue(rootNode.getChildren().get(0).getChildren().get(0) instanceof 
LimitNode);
+    limitNode = (LimitNode) rootNode.getChildren().get(0).getChildren().get(0);
+    assertEquals(5, limitNode.getCount());
+    offsetNode = (OffsetNode) limitNode.getChild();
+    assertEquals(3, offsetNode.getCount());
+  }
+
+  @Test
+  public void sortTest() {
+    // when TableScan locates multi regions, use default MergeSortNode
+    sql = "SELECT * FROM table1 ";
+    context = new MPPQueryContext(sql, queryId, sessionInfo, null, null);
+    actualAnalysis = analyzeSQL(sql, metadata);
+    logicalQueryPlan =
+        new LogicalPlanner(context, metadata, sessionInfo, 
WarningCollector.NOOP)
+            .plan(actualAnalysis);
+    rootNode = logicalQueryPlan.getRootNode();
+    distributedQueryPlan =
+        new TableDistributionPlanner(actualAnalysis, logicalQueryPlan, 
context).plan();
+  }
+
   public static Analysis analyzeSQL(String sql, Metadata metadata) {
     try {
       SqlParser sqlParser = new SqlParser();
@@ -508,80 +513,5 @@ public class AnalyzerTest {
     return null;
   }
 
-  private static final DataPartition DATA_PARTITION = 
MockTablePartition.constructDataPartition();
-  private static final SchemaPartition SCHEMA_PARTITION =
-      MockTablePartition.constructSchemaPartition();
-
-  private static IPartitionFetcher getFakePartitionFetcher() {
-
-    return new IPartitionFetcher() {
-
-      @Override
-      public SchemaPartition getSchemaPartition(PathPatternTree patternTree) {
-        return SCHEMA_PARTITION;
-      }
-
-      @Override
-      public SchemaPartition getOrCreateSchemaPartition(
-          PathPatternTree patternTree, String userName) {
-        return SCHEMA_PARTITION;
-      }
-
-      @Override
-      public DataPartition getDataPartition(
-          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
-        return DATA_PARTITION;
-      }
-
-      @Override
-      public DataPartition getDataPartitionWithUnclosedTimeRange(
-          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
-        return DATA_PARTITION;
-      }
-
-      @Override
-      public DataPartition getOrCreateDataPartition(
-          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
-        return DATA_PARTITION;
-      }
-
-      @Override
-      public DataPartition getOrCreateDataPartition(
-          List<DataPartitionQueryParam> dataPartitionQueryParams, String 
userName) {
-        return DATA_PARTITION;
-      }
-
-      @Override
-      public SchemaNodeManagementPartition 
getSchemaNodeManagementPartitionWithLevel(
-          PathPatternTree patternTree, PathPatternTree scope, Integer level) {
-        return null;
-      }
-
-      @Override
-      public boolean updateRegionCache(TRegionRouteReq req) {
-        return false;
-      }
-
-      @Override
-      public void invalidAllCache() {}
-
-      @Override
-      public SchemaPartition getOrCreateSchemaPartition(
-          String database, List<IDeviceID> deviceIDList, String userName) {
-        return null;
-      }
-
-      @Override
-      public SchemaPartition getSchemaPartition(String database, 
List<IDeviceID> deviceIDList) {
-        return null;
-      }
-
-      @Override
-      public SchemaPartition getSchemaPartition(String database) {
-        return null;
-      }
-    };
-  }
-
   private static class NopAccessControl implements AccessControl {}
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
index 4c483f4c8fa..f0425d91dc7 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
@@ -14,11 +14,16 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 
+import org.apache.iotdb.commons.partition.DataPartition;
+import org.apache.iotdb.commons.partition.DataPartitionQueryParam;
+import org.apache.iotdb.commons.partition.SchemaNodeManagementPartition;
 import org.apache.iotdb.commons.partition.SchemaPartition;
+import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
 import org.apache.iotdb.commons.udf.builtin.BuiltinAggregationFunction;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
+import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnMetadata;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema;
@@ -34,6 +39,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
 import org.apache.iotdb.db.queryengine.plan.relational.type.TypeManager;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.TypeNotFoundException;
 import org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignature;
+import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
 
 import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.file.metadata.StringArrayDeviceID;
@@ -43,6 +49,7 @@ import org.apache.tsfile.read.common.type.Type;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Optional;
 
 import static 
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableMetadataImpl.getFunctionType;
@@ -177,6 +184,11 @@ public class TestMatadata implements Metadata {
     return true;
   }
 
+  @Override
+  public IPartitionFetcher getPartitionFetcher() {
+    return getFakePartitionFetcher();
+  }
+
   @Override
   public List<DeviceEntry> indexScan(
       QualifiedObjectName tableName,
@@ -251,4 +263,79 @@ public class TestMatadata implements Metadata {
     // Boolean type and Binary Type can not be compared with other types
     return isNumericType(left) && isNumericType(right);
   }
+
+  private static final DataPartition DATA_PARTITION = 
MockTablePartition.constructDataPartition();
+  private static final SchemaPartition SCHEMA_PARTITION =
+      MockTablePartition.constructSchemaPartition();
+
+  private static IPartitionFetcher getFakePartitionFetcher() {
+
+    return new IPartitionFetcher() {
+
+      @Override
+      public SchemaPartition getSchemaPartition(PathPatternTree patternTree) {
+        return SCHEMA_PARTITION;
+      }
+
+      @Override
+      public SchemaPartition getOrCreateSchemaPartition(
+          PathPatternTree patternTree, String userName) {
+        return SCHEMA_PARTITION;
+      }
+
+      @Override
+      public DataPartition getDataPartition(
+          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
+        return DATA_PARTITION;
+      }
+
+      @Override
+      public DataPartition getDataPartitionWithUnclosedTimeRange(
+          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
+        return DATA_PARTITION;
+      }
+
+      @Override
+      public DataPartition getOrCreateDataPartition(
+          Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap) {
+        return DATA_PARTITION;
+      }
+
+      @Override
+      public DataPartition getOrCreateDataPartition(
+          List<DataPartitionQueryParam> dataPartitionQueryParams, String 
userName) {
+        return DATA_PARTITION;
+      }
+
+      @Override
+      public SchemaNodeManagementPartition 
getSchemaNodeManagementPartitionWithLevel(
+          PathPatternTree patternTree, PathPatternTree scope, Integer level) {
+        return null;
+      }
+
+      @Override
+      public boolean updateRegionCache(TRegionRouteReq req) {
+        return false;
+      }
+
+      @Override
+      public void invalidAllCache() {}
+
+      @Override
+      public SchemaPartition getOrCreateSchemaPartition(
+          String database, List<IDeviceID> deviceIDList, String userName) {
+        return null;
+      }
+
+      @Override
+      public SchemaPartition getSchemaPartition(String database, 
List<IDeviceID> deviceIDList) {
+        return null;
+      }
+
+      @Override
+      public SchemaPartition getSchemaPartition(String database) {
+        return null;
+      }
+    };
+  }
 }

Reply via email to