You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by xi...@apache.org on 2021/05/25 16:09:04 UTC

[iotdb] 02/06: Restructure query operator

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

xiangweiwei pushed a commit to branch RequeryV2
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit ad89e3a6f9d833bf8e624d0036fb79af2c35430c
Author: Alima777 <wx...@gmail.com>
AuthorDate: Wed May 19 21:15:56 2021 +0800

    Restructure query operator
---
 .../query/ClusterPhysicalGeneratorTest.java        |  20 +-
 ...Operator.java => AggregationQueryOperator.java} |  26 +-
 ...{FromOperator.java => FillClauseComponent.java} |  26 +-
 .../{FromOperator.java => FillQueryOperator.java}  |  26 +-
 .../iotdb/db/qp/logical/crud/FilterOperator.java   |   9 +-
 .../crud/{FromOperator.java => FromComponent.java} |  11 +-
 .../db/qp/logical/crud/GroupByClauseComponent.java |  91 +++++++
 ...erator.java => GroupByFillClauseComponent.java} |  26 +-
 ...Operator.java => GroupByFillQueryOperator.java} |  26 +-
 ...rator.java => GroupByLevelClauseComponent.java} |  26 +-
 ...FromOperator.java => GroupByQueryOperator.java} |  26 +-
 .../{FromOperator.java => LastQueryOperator.java}  |  28 +--
 .../iotdb/db/qp/logical/crud/QueryOperator.java    | 270 +++------------------
 .../{SelectOperator.java => SelectComponent.java}  |  16 +-
 .../db/qp/logical/crud/SpecialClauseComponent.java | 128 ++++++++++
 .../{FromOperator.java => UDFQueryOperator.java}   |  26 +-
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    | 260 +++++++++++++-------
 .../iotdb/db/qp/strategy/LogicalChecker.java       |  21 +-
 .../iotdb/db/qp/strategy/LogicalGenerator.java     |  14 +-
 .../iotdb/db/qp/strategy/PhysicalGenerator.java    |  99 ++++----
 .../qp/strategy/optimizer/ConcatPathOptimizer.java |  27 ++-
 .../apache/iotdb/db/qp/utils/WildcardsRemover.java |  27 +--
 .../iotdb/db/integration/IoTDBGroupByFillIT.java   |   2 +-
 .../iotdb/db/qp/logical/IndexLogicalPlanTest.java  |   8 +-
 .../iotdb/db/qp/logical/LogicalPlanSmallTest.java  |  76 +++---
 25 files changed, 613 insertions(+), 702 deletions(-)

diff --git a/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java b/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
index f1d7d57..fdbe72f 100644
--- a/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
+++ b/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
@@ -23,10 +23,9 @@ import org.apache.iotdb.cluster.common.TestUtils;
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.constant.SQLConstant;
-import org.apache.iotdb.db.qp.logical.crud.FromOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromComponent;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
 import org.apache.iotdb.db.qp.physical.crud.RawDataQueryPlan;
 import org.apache.iotdb.db.query.expression.ResultColumn;
 import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
@@ -53,20 +52,19 @@ public class ClusterPhysicalGeneratorTest extends BaseQueryTest {
 
   @Test
   public void test() throws QueryProcessException, IllegalPathException {
-    QueryOperator operator = new QueryOperator(SQLConstant.TOK_QUERY);
+    QueryOperator operator = new QueryOperator();
 
-    SelectOperator selectOperator =
-        new SelectOperator(SQLConstant.TOK_SELECT, ZoneId.systemDefault());
+    SelectComponent selectComponent = new SelectComponent(ZoneId.systemDefault());
     List<ResultColumn> resultColumns = new ArrayList<>();
     for (PartialPath partialPath : pathList) {
       resultColumns.add(new ResultColumn(new TimeSeriesOperand(partialPath)));
     }
-    selectOperator.setResultColumns(resultColumns);
-    FromOperator fromOperator = new FromOperator(SQLConstant.TOK_FROM);
-    fromOperator.addPrefixTablePath(new PartialPath(TestUtils.getTestSg(0)));
+    selectComponent.setResultColumns(resultColumns);
+    FromComponent fromComponent = new FromComponent();
+    fromComponent.addPrefixTablePath(new PartialPath(TestUtils.getTestSg(0)));
 
-    operator.setSelectOperator(selectOperator);
-    operator.setFromOperator(fromOperator);
+    operator.setSelectComponent(selectComponent);
+    operator.setFromComponent(fromComponent);
     RawDataQueryPlan plan =
         (RawDataQueryPlan) physicalGenerator.transformToPhysicalPlan(operator, 1024);
 
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/AggregationQueryOperator.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/AggregationQueryOperator.java
index 60fed66..fd790ff 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/AggregationQueryOperator.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class AggregationQueryOperator extends QueryOperator {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillClauseComponent.java
similarity index 59%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillClauseComponent.java
index 60fed66..5750ac7 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillClauseComponent.java
@@ -18,28 +18,22 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.query.executor.fill.IFill;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
+public class FillClauseComponent extends SpecialClauseComponent {
 
-  private List<PartialPath> prefixList;
+  private Map<TSDataType, IFill> fillTypes;
 
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
+  public FillClauseComponent() {}
 
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
+  public Map<TSDataType, IFill> getFillTypes() {
+    return fillTypes;
   }
 
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
+  public void setFillTypes(Map<TSDataType, IFill> fillTypes) {
+    this.fillTypes = fillTypes;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillQueryOperator.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillQueryOperator.java
index 60fed66..985ae16 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FillQueryOperator.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class FillQueryOperator extends QueryOperator {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java
index 315223e..9fa4c87 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java
@@ -47,13 +47,13 @@ import static org.apache.iotdb.db.qp.constant.SQLConstant.KW_OR;
  */
 public class FilterOperator extends Operator implements Comparable<FilterOperator> {
 
-  // it is the symbol of token. e.g. AND is & and OR is |
+  // The symbol of token. e.g. AND is & and OR is |
   String tokenSymbol;
 
-  private List<FilterOperator> childOperators;
+  private List<FilterOperator> childOperators = new ArrayList<>();
   // leaf filter operator means it doesn't have left and right child filterOperator. Leaf filter
   // should set FunctionOperator.
-  protected boolean isLeaf;
+  protected boolean isLeaf = false;
   // isSingle being true means all recursive children of this filter belong to one seriesPath.
   boolean isSingle = false;
   // if isSingle = false, singlePath must be null
@@ -64,9 +64,6 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato
   public FilterOperator(int tokenType) {
     super(tokenType);
     operatorType = OperatorType.FILTER;
-    childOperators = new ArrayList<>();
-    this.tokenIntType = tokenType;
-    isLeaf = false;
     tokenSymbol = SQLConstant.tokenSymbol.get(tokenType);
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromComponent.java
similarity index 81%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromComponent.java
index 60fed66..16b56d1 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromComponent.java
@@ -19,21 +19,16 @@
 package org.apache.iotdb.db.qp.logical.crud;
 
 import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
+public class FromComponent {
 
-  private List<PartialPath> prefixList;
+  private List<PartialPath> prefixList = new ArrayList<>();;
 
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
+  public FromComponent() {}
 
   public void addPrefixTablePath(PartialPath prefixPath) {
     prefixList.add(prefixPath);
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByClauseComponent.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByClauseComponent.java
new file mode 100644
index 0000000..46b3987
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByClauseComponent.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.qp.logical.crud;
+
+public class GroupByClauseComponent extends SpecialClauseComponent {
+
+  private long startTime;
+  private long endTime;
+  // time interval
+  private long unit;
+  // sliding step
+  private long slidingStep;
+  private boolean isIntervalByMonth = false;
+  private boolean isSlidingStepByMonth = false;
+  // if it is left close and right open interval
+  private boolean leftCRightO;
+
+  public GroupByClauseComponent() {}
+
+  public boolean isLeftCRightO() {
+    return leftCRightO;
+  }
+
+  public void setLeftCRightO(boolean leftCRightO) {
+    this.leftCRightO = leftCRightO;
+  }
+
+  public long getUnit() {
+    return unit;
+  }
+
+  public void setUnit(long unit) {
+    this.unit = unit;
+  }
+
+  public long getStartTime() {
+    return startTime;
+  }
+
+  public void setStartTime(long startTime) {
+    this.startTime = startTime;
+  }
+
+  public long getEndTime() {
+    return endTime;
+  }
+
+  public void setEndTime(long endTime) {
+    this.endTime = endTime;
+  }
+
+  public long getSlidingStep() {
+    return slidingStep;
+  }
+
+  public void setSlidingStep(long slidingStep) {
+    this.slidingStep = slidingStep;
+  }
+
+  public boolean isSlidingStepByMonth() {
+    return isSlidingStepByMonth;
+  }
+
+  public void setSlidingStepByMonth(boolean isSlidingStepByMonth) {
+    this.isSlidingStepByMonth = isSlidingStepByMonth;
+  }
+
+  public boolean isIntervalByMonth() {
+    return isIntervalByMonth;
+  }
+
+  public void setIntervalByMonth(boolean isIntervalByMonth) {
+    this.isIntervalByMonth = isIntervalByMonth;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillClauseComponent.java
similarity index 59%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillClauseComponent.java
index 60fed66..616bd59 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillClauseComponent.java
@@ -18,28 +18,22 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.query.executor.fill.IFill;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
+public class GroupByFillClauseComponent extends GroupByClauseComponent {
 
-  private List<PartialPath> prefixList;
+  private Map<TSDataType, IFill> fillTypes;
 
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
+  public GroupByFillClauseComponent() {}
 
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
+  public Map<TSDataType, IFill> getFillTypes() {
+    return fillTypes;
   }
 
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
+  public void setFillTypes(Map<TSDataType, IFill> fillTypes) {
+    this.fillTypes = fillTypes;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillQueryOperator.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillQueryOperator.java
index 60fed66..79cfade 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByFillQueryOperator.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class GroupByFillQueryOperator extends GroupByQueryOperator {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByLevelClauseComponent.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByLevelClauseComponent.java
index 60fed66..5774265 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByLevelClauseComponent.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class GroupByLevelClauseComponent extends SpecialClauseComponent {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByQueryOperator.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByQueryOperator.java
index 60fed66..ec9a938 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/GroupByQueryOperator.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class GroupByQueryOperator extends QueryOperator {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LastQueryOperator.java
similarity index 58%
copy from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LastQueryOperator.java
index 60fed66..51b43c6 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LastQueryOperator.java
@@ -18,28 +18,14 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
+public class LastQueryOperator extends QueryOperator {
 
-import java.util.ArrayList;
-import java.util.List;
+  public LastQueryOperator() {}
 
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
+  public LastQueryOperator(QueryOperator queryOperator) {
+    this.selectComponent = queryOperator.getSelectComponent();
+    this.fromComponent = queryOperator.getFromComponent();
+    this.filterOperator = queryOperator.getFilterOperator();
+    this.specialClauseComponent = queryOperator.getSpecialClauseComponent();
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
index 7e3055b..2e70cf3 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
@@ -19,78 +19,42 @@
 package org.apache.iotdb.db.qp.logical.crud;
 
 import org.apache.iotdb.db.index.common.IndexType;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.RootOperator;
-import org.apache.iotdb.db.query.executor.fill.IFill;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
 import java.util.Map;
 
 public class QueryOperator extends RootOperator {
 
-  private SelectOperator selectOperator;
-  private FromOperator fromOperator;
-  private FilterOperator filterOperator;
+  protected SelectComponent selectComponent;
+  protected FromComponent fromComponent;
+  protected FilterOperator filterOperator;
+  protected SpecialClauseComponent specialClauseComponent;
 
-  private long startTime;
-  private long endTime;
-  // time interval
-  private long unit;
-  // sliding step
-  private long slidingStep;
-  private boolean isGroupByTime = false;
-  private boolean isIntervalByMonth = false;
-  private boolean isSlidingStepByMonth = false;
-  // if it is left close and right open interval
-  private boolean leftCRightO;
+  protected Map<String, Object> props;
 
-  private Map<TSDataType, IFill> fillTypes;
-  private boolean isFill = false;
+  protected IndexType indexType;
 
-  private boolean isGroupByLevel = false;
-  private int level = -1;
-
-  private int rowLimit = 0;
-  private int rowOffset = 0;
-  private int seriesLimit = 0;
-  private int seriesOffset = 0;
-
-  private boolean isAlignByDevice = false;
-  private boolean isAlignByTime = true;
-
-  private String column;
-
-  private boolean ascending = true;
-
-  private Map<String, Object> props;
-
-  private IndexType indexType;
-
-  // if true, we don't need the row whose any column is null
-  private boolean withoutAnyNull;
-
-  // if true, we don't need the row whose all columns are null
-  private boolean withoutAllNull;
-
-  public QueryOperator(int tokenIntType) {
-    super(tokenIntType);
+  public QueryOperator() {
+    super(SQLConstant.TOK_QUERY);
     operatorType = Operator.OperatorType.QUERY;
   }
 
-  public SelectOperator getSelectOperator() {
-    return selectOperator;
+  public SelectComponent getSelectComponent() {
+    return selectComponent;
   }
 
-  public void setSelectOperator(SelectOperator selectOperator) {
-    this.selectOperator = selectOperator;
+  public void setSelectComponent(SelectComponent selectComponent) {
+    this.selectComponent = selectComponent;
   }
 
-  public FromOperator getFromOperator() {
-    return fromOperator;
+  public FromComponent getFromComponent() {
+    return fromComponent;
   }
 
-  public void setFromOperator(FromOperator fromOperator) {
-    this.fromOperator = fromOperator;
+  public void setFromComponent(FromComponent fromComponent) {
+    this.fromComponent = fromComponent;
   }
 
   public FilterOperator getFilterOperator() {
@@ -101,6 +65,14 @@ public class QueryOperator extends RootOperator {
     this.filterOperator = filterOperator;
   }
 
+  public void setSpecialClauseComponent(SpecialClauseComponent specialClauseComponent) {
+    this.specialClauseComponent = specialClauseComponent;
+  }
+
+  public SpecialClauseComponent getSpecialClauseComponent() {
+    return specialClauseComponent;
+  }
+
   public Map<String, Object> getProps() {
     return props;
   }
@@ -117,199 +89,23 @@ public class QueryOperator extends RootOperator {
     this.indexType = indexType;
   }
 
-  public boolean isFill() {
-    return isFill;
-  }
-
-  public void setFill(boolean fill) {
-    isFill = fill;
-  }
-
-  public Map<TSDataType, IFill> getFillTypes() {
-    return fillTypes;
-  }
-
-  public void setFillTypes(Map<TSDataType, IFill> fillTypes) {
-    this.fillTypes = fillTypes;
-  }
-
-  public boolean isGroupByLevel() {
-    return isGroupByLevel;
-  }
-
-  public void setGroupByLevel(boolean isGroupBy) {
-    this.isGroupByLevel = isGroupBy;
-  }
-
-  public boolean isLeftCRightO() {
-    return leftCRightO;
-  }
-
-  public void setLeftCRightO(boolean leftCRightO) {
-    this.leftCRightO = leftCRightO;
-  }
-
-  public int getRowLimit() {
-    return rowLimit;
-  }
-
-  public void setRowLimit(int rowLimit) {
-    this.rowLimit = rowLimit;
-  }
-
-  public int getRowOffset() {
-    return rowOffset;
-  }
-
-  public void setRowOffset(int rowOffset) {
-    this.rowOffset = rowOffset;
-  }
-
-  public boolean hasLimit() {
-    return rowLimit > 0;
-  }
-
-  public int getSeriesLimit() {
-    return seriesLimit;
-  }
-
-  public void setSeriesLimit(int seriesLimit) {
-    this.seriesLimit = seriesLimit;
-  }
-
-  public int getSeriesOffset() {
-    return seriesOffset;
-  }
-
-  public void setSeriesOffset(int seriesOffset) {
-    this.seriesOffset = seriesOffset;
-  }
-
-  public boolean hasSlimit() {
-    return seriesLimit > 0;
-  }
-
-  public long getUnit() {
-    return unit;
-  }
-
-  public void setUnit(long unit) {
-    this.unit = unit;
-  }
-
-  public long getStartTime() {
-    return startTime;
-  }
-
-  public void setStartTime(long startTime) {
-    this.startTime = startTime;
-  }
-
-  public long getEndTime() {
-    return endTime;
-  }
-
-  public void setEndTime(long endTime) {
-    this.endTime = endTime;
-  }
-
-  public long getSlidingStep() {
-    return slidingStep;
-  }
-
-  public void setSlidingStep(long slidingStep) {
-    this.slidingStep = slidingStep;
-  }
-
-  public boolean isAlignByDevice() {
-    return isAlignByDevice;
-  }
-
-  public void setAlignByDevice(boolean isAlignByDevice) {
-    this.isAlignByDevice = isAlignByDevice;
-  }
-
-  public boolean isAlignByTime() {
-    return isAlignByTime;
-  }
-
-  public void setAlignByTime(boolean isAlignByTime) {
-    this.isAlignByTime = isAlignByTime;
-  }
-
-  public int getLevel() {
-    return level;
-  }
-
-  public void setLevel(int level) {
-    this.level = level;
-  }
-
-  public boolean isGroupByTime() {
-    return isGroupByTime;
-  }
-
-  public void setGroupByTime(boolean groupByTime) {
-    isGroupByTime = groupByTime;
-  }
-
-  public boolean isSlidingStepByMonth() {
-    return isSlidingStepByMonth;
-  }
-
-  public void setSlidingStepByMonth(boolean isSlidingStepByMonth) {
-    this.isSlidingStepByMonth = isSlidingStepByMonth;
-  }
-
-  public boolean isIntervalByMonth() {
-    return isIntervalByMonth;
-  }
-
-  public void setIntervalByMonth(boolean isIntervalByMonth) {
-    this.isIntervalByMonth = isIntervalByMonth;
-  }
-
-  public String getColumn() {
-    return column;
-  }
-
-  public void setColumn(String column) {
-    this.column = column;
-  }
-
-  public boolean isAscending() {
-    return ascending;
-  }
-
-  public void setAscending(boolean ascending) {
-    this.ascending = ascending;
-  }
-
-  public boolean isLastQuery() {
-    return selectOperator.isLastQuery();
-  }
-
   public boolean hasAggregationFunction() {
-    return selectOperator.hasAggregationFunction();
+    return selectComponent.hasAggregationFunction();
   }
 
   public boolean hasTimeSeriesGeneratingFunction() {
-    return selectOperator.hasTimeSeriesGeneratingFunction();
-  }
-
-  public boolean isWithoutAnyNull() {
-    return withoutAnyNull;
+    return selectComponent.hasTimeSeriesGeneratingFunction();
   }
 
-  public void setWithoutAnyNull(boolean withoutAnyNull) {
-    this.withoutAnyNull = withoutAnyNull;
+  public boolean isAlignByDevice() {
+    return specialClauseComponent != null && specialClauseComponent.isAlignByDevice();
   }
 
-  public boolean isWithoutAllNull() {
-    return withoutAllNull;
+  public boolean isAlignByTime() {
+    return specialClauseComponent == null || specialClauseComponent.isAlignByTime();
   }
 
-  public void setWithoutAllNull(boolean withoutAllNull) {
-    this.withoutAllNull = withoutAllNull;
+  public boolean isGroupByLevel() {
+    return specialClauseComponent != null && specialClauseComponent.getLevel() != -1;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
similarity index 90%
rename from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java
rename to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
index 4c260b9..11bd80b 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
@@ -19,7 +19,6 @@
 package org.apache.iotdb.db.qp.logical.crud;
 
 import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.query.expression.Expression;
 import org.apache.iotdb.db.query.expression.ResultColumn;
 import org.apache.iotdb.db.query.expression.unary.FunctionExpression;
@@ -30,11 +29,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 /** this class maintains information from select clause. */
-public final class SelectOperator extends Operator {
+public final class SelectComponent {
 
   private final ZoneId zoneId;
 
-  private boolean isLastQuery = false;
   private boolean hasAggregationFunction = false;
   private boolean hasTimeSeriesGeneratingFunction = false;
 
@@ -44,9 +42,7 @@ public final class SelectOperator extends Operator {
   private List<String> aggregationFunctionsCache;
 
   /** init with tokenIntType, default operatorType is <code>OperatorType.SELECT</code>. */
-  public SelectOperator(int tokenIntType, ZoneId zoneId) {
-    super(tokenIntType);
-    operatorType = OperatorType.SELECT;
+  public SelectComponent(ZoneId zoneId) {
     this.zoneId = zoneId;
   }
 
@@ -54,14 +50,6 @@ public final class SelectOperator extends Operator {
     return zoneId;
   }
 
-  public void markAsLastQuery() {
-    isLastQuery = true;
-  }
-
-  public boolean isLastQuery() {
-    return isLastQuery;
-  }
-
   public boolean hasAggregationFunction() {
     return hasAggregationFunction;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SpecialClauseComponent.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SpecialClauseComponent.java
new file mode 100644
index 0000000..63de6fd
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SpecialClauseComponent.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.qp.logical.crud;
+
+public class SpecialClauseComponent {
+
+  private int rowLimit = 0;
+  private int rowOffset = 0;
+  private int seriesLimit = 0;
+  private int seriesOffset = 0;
+
+  private boolean ascending = true;
+  // if true, we don't need the row whose any column is null
+  private boolean withoutAnyNull;
+  // if true, we don't need the row whose all columns are null
+  private boolean withoutAllNull;
+
+  private int level = -1;
+
+  private boolean isAlignByDevice = false;
+  private boolean isAlignByTime = true;
+
+  public SpecialClauseComponent() {}
+
+  public int getRowLimit() {
+    return rowLimit;
+  }
+
+  public void setRowLimit(int rowLimit) {
+    this.rowLimit = rowLimit;
+  }
+
+  public int getRowOffset() {
+    return rowOffset;
+  }
+
+  public void setRowOffset(int rowOffset) {
+    this.rowOffset = rowOffset;
+  }
+
+  public boolean hasLimit() {
+    return rowLimit > 0;
+  }
+
+  public int getSeriesLimit() {
+    return seriesLimit;
+  }
+
+  public void setSeriesLimit(int seriesLimit) {
+    this.seriesLimit = seriesLimit;
+  }
+
+  public int getSeriesOffset() {
+    return seriesOffset;
+  }
+
+  public void setSeriesOffset(int seriesOffset) {
+    this.seriesOffset = seriesOffset;
+  }
+
+  public boolean hasSlimit() {
+    return seriesLimit > 0;
+  }
+
+  public boolean isAscending() {
+    return ascending;
+  }
+
+  public void setAscending(boolean ascending) {
+    this.ascending = ascending;
+  }
+
+  public boolean isWithoutAnyNull() {
+    return withoutAnyNull;
+  }
+
+  public void setWithoutAnyNull(boolean withoutAnyNull) {
+    this.withoutAnyNull = withoutAnyNull;
+  }
+
+  public boolean isWithoutAllNull() {
+    return withoutAllNull;
+  }
+
+  public void setWithoutAllNull(boolean withoutAllNull) {
+    this.withoutAllNull = withoutAllNull;
+  }
+
+  public int getLevel() {
+    return level;
+  }
+
+  public void setLevel(int level) {
+    this.level = level;
+  }
+
+  public boolean isAlignByDevice() {
+    return isAlignByDevice;
+  }
+
+  public void setAlignByDevice(boolean isAlignByDevice) {
+    this.isAlignByDevice = isAlignByDevice;
+  }
+
+  public boolean isAlignByTime() {
+    return isAlignByTime;
+  }
+
+  public void setAlignByTime(boolean isAlignByTime) {
+    this.isAlignByTime = isAlignByTime;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java
similarity index 58%
rename from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
rename to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java
index 60fed66..49a6814 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FromOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java
@@ -18,28 +18,4 @@
  */
 package org.apache.iotdb.db.qp.logical.crud;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.logical.Operator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** this class maintains information of {@code FROM} clause. */
-public class FromOperator extends Operator {
-
-  private List<PartialPath> prefixList;
-
-  public FromOperator(int tokenIntType) {
-    super(tokenIntType);
-    operatorType = OperatorType.FROM;
-    prefixList = new ArrayList<>();
-  }
-
-  public void addPrefixTablePath(PartialPath prefixPath) {
-    prefixList.add(prefixPath);
-  }
-
-  public List<PartialPath> getPrefixPaths() {
-    return prefixList;
-  }
-}
+public class UDFQueryOperator extends QueryOperator {}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 44d9131..0212a0f 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -27,14 +27,24 @@ import org.apache.iotdb.db.index.common.IndexUtils;
 import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.crud.AggregationQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator;
+import org.apache.iotdb.db.qp.logical.crud.FillClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.FillQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
-import org.apache.iotdb.db.qp.logical.crud.FromOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByFillClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByFillQueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.GroupByLevelClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.InOperator;
 import org.apache.iotdb.db.qp.logical.crud.InsertOperator;
+import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
+import org.apache.iotdb.db.qp.logical.crud.SpecialClauseComponent;
 import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator;
 import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator.AlterType;
 import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
@@ -77,7 +87,6 @@ import org.apache.iotdb.db.qp.logical.sys.ShowTriggersOperator;
 import org.apache.iotdb.db.qp.logical.sys.StartTriggerOperator;
 import org.apache.iotdb.db.qp.logical.sys.StopTriggerOperator;
 import org.apache.iotdb.db.qp.logical.sys.TracingOperator;
-import org.apache.iotdb.db.qp.physical.crud.GroupByTimePlan;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.AliasClauseContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignStatementContext;
@@ -208,6 +217,7 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.TriggerAttributeContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.TypeClauseContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.UnsetTTLStatementContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.WhereClauseContext;
+import org.apache.iotdb.db.qp.sql.SqlBaseParser.WithoutNullClauseContext;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser.WithoutNullStatementContext;
 import org.apache.iotdb.db.qp.utils.DatetimeUtils;
 import org.apache.iotdb.db.query.executor.fill.IFill;
@@ -257,7 +267,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
       "For delete statement, where clause can only contain atomic expressions like : "
           + "time > XXX, time <= XXX, or two atomic expressions connected by 'AND'";
   private ZoneId zoneId;
-  QueryOperator queryOp;
+  private QueryOperator queryOp;
 
   public void setZoneId(ZoneId zoneId) {
     this.zoneId = zoneId;
@@ -988,37 +998,42 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitSelectStatement(SelectStatementContext ctx) {
-    queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
-    queryOp.setSelectOperator((SelectOperator) visit(ctx.selectClause()));
-    queryOp.setFromOperator((FromOperator) visit(ctx.fromClause()));
+    // 1. Visit special clause first to initialize different query operator
+    if (ctx.specialClause() != null) {
+      queryOp = (QueryOperator) visit(ctx.specialClause());
+    }
+    // 2. There is no special clause in query statement.
+    if (queryOp == null) {
+      queryOp = new QueryOperator();
+    }
+    // 3. Visit select, from, where in sequence
+    parseSelectClause(ctx.selectClause());
+    parseFromClause(ctx.fromClause());
     if (ctx.whereClause() != null) {
       Operator operator = visit(ctx.whereClause());
       if (operator instanceof FilterOperator) {
         queryOp.setFilterOperator(((FilterOperator) operator).getChildren().get(0));
       }
     }
-    if (ctx.specialClause() != null) {
-      visit(ctx.specialClause());
-    }
+
     return queryOp;
   }
 
-  @Override
-  public Operator visitSelectClause(SelectClauseContext ctx) {
-    SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId);
+  public void parseSelectClause(SelectClauseContext ctx) {
+    SelectComponent selectComponent = new SelectComponent(zoneId);
 
     if (ctx.topClause() != null) {
       // TODO: parse info of top clause into selectOp
       visitTopClause(ctx.topClause());
     } else if (ctx.LAST() != null) {
-      selectOp.markAsLastQuery();
+      queryOp = new LastQueryOperator(queryOp);
     }
 
     for (ResultColumnContext resultColumnContext : ctx.resultColumn()) {
-      selectOp.addResultColumn(parseResultColumn(resultColumnContext));
+      selectComponent.addResultColumn(parseResultColumn(resultColumnContext));
     }
 
-    return selectOp;
+    queryOp.setSelectComponent(selectComponent);
   }
 
   @Override
@@ -1105,9 +1120,12 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitLimitStatement(LimitStatementContext ctx) {
+    if (queryOp == null) {
+      queryOp = new QueryOperator();
+    }
     parseLimitClause(ctx.limitClause(), queryOp);
     if (ctx.slimitClause() != null) {
-      parseSlimitClause(ctx.slimitClause(), queryOp);
+      parseSlimitClause(ctx.slimitClause());
     }
     if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
       parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
@@ -1117,7 +1135,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitSlimitStatement(SlimitStatementContext ctx) {
-    parseSlimitClause(ctx.slimitClause(), queryOp);
+    if (queryOp == null) {
+      queryOp = new QueryOperator();
+    }
+    parseSlimitClause(ctx.slimitClause());
     if (ctx.limitClause() != null) {
       parseLimitClause(ctx.limitClause(), queryOp);
     }
@@ -1130,30 +1151,38 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
   @Override
   public Operator visitAlignByDeviceClauseOrDisableAlignStatement(
       AlignByDeviceClauseOrDisableAlignStatementContext ctx) {
+    if (queryOp == null) {
+      queryOp = new QueryOperator();
+    }
     parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
     return queryOp;
   }
 
   private void parseAlignByDeviceClauseOrDisableAlign(
       AlignByDeviceClauseOrDisableAlignContext ctx) {
+    SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+    if (specialClauseComponent == null) {
+      specialClauseComponent = new SpecialClauseComponent();
+    }
     if (ctx.alignByDeviceClause() != null) {
-      parseAlignByDeviceClause(queryOp);
+      parseAlignByDeviceClause(specialClauseComponent);
     } else {
-      parseDisableAlign(queryOp);
+      parseDisableAlign(specialClauseComponent);
     }
+    queryOp.setSpecialClauseComponent(specialClauseComponent);
   }
 
   @Override
   public Operator visitWithoutNullStatement(WithoutNullStatementContext ctx) {
-    if (ctx.withoutNullClause().WITHOUT() != null) {
-      queryOp.setWithoutAllNull(ctx.withoutNullClause().ALL() != null);
-      queryOp.setWithoutAnyNull(ctx.withoutNullClause().ANY() != null);
+    if (queryOp == null) {
+      queryOp = new QueryOperator();
     }
+    parseWithoutNullClause(ctx.withoutNullClause());
     if (ctx.limitClause() != null) {
       parseLimitClause(ctx.limitClause(), queryOp);
     }
     if (ctx.slimitClause() != null) {
-      parseSlimitClause(ctx.slimitClause(), queryOp);
+      parseSlimitClause(ctx.slimitClause());
     }
     if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
       parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
@@ -1161,9 +1190,20 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     return queryOp;
   }
 
+  private void parseWithoutNullClause(WithoutNullClauseContext ctx) {
+    SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+    if (specialClauseComponent == null) {
+      specialClauseComponent = new SpecialClauseComponent();
+    }
+    specialClauseComponent.setWithoutAnyNull(ctx.ANY() != null);
+    specialClauseComponent.setWithoutAllNull(ctx.ALL() != null);
+    queryOp.setSpecialClauseComponent(specialClauseComponent);
+  }
+
   @Override
   public Operator visitOrderByTimeStatement(OrderByTimeStatementContext ctx) {
-    parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp);
+    queryOp = new QueryOperator();
+    parseOrderByTimeClause(ctx.orderByTimeClause());
     if (ctx.specialLimit() != null) {
       return visit(ctx.specialLimit());
     }
@@ -1172,9 +1212,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitGroupByTimeStatement(GroupByTimeStatementContext ctx) {
-    parseGroupByTimeClause(ctx.groupByTimeClause(), queryOp);
+    queryOp = new GroupByQueryOperator();
+    parseGroupByTimeClause(ctx.groupByTimeClause());
     if (ctx.orderByTimeClause() != null) {
-      parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp);
+      parseOrderByTimeClause(ctx.orderByTimeClause());
     }
     if (ctx.specialLimit() != null) {
       return visit(ctx.specialLimit());
@@ -1184,9 +1225,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitGroupByFillStatement(GroupByFillStatementContext ctx) {
-    parseGroupByFillClause(ctx.groupByFillClause(), queryOp);
+    queryOp = new GroupByFillQueryOperator();
+    parseGroupByFillClause(ctx.groupByFillClause());
     if (ctx.orderByTimeClause() != null) {
-      parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp);
+      parseOrderByTimeClause(ctx.orderByTimeClause());
     }
     if (ctx.specialLimit() != null) {
       return visit(ctx.specialLimit());
@@ -1196,9 +1238,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitFillStatement(FillStatementContext ctx) {
-    parseFillClause(ctx.fillClause(), queryOp);
+    queryOp = new FillQueryOperator();
+    parseFillClause(ctx.fillClause());
     if (ctx.slimitClause() != null) {
-      parseSlimitClause(ctx.slimitClause(), queryOp);
+      parseSlimitClause(ctx.slimitClause());
     }
     if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
       parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
@@ -1208,9 +1251,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
 
   @Override
   public Operator visitGroupByLevelStatement(GroupByLevelStatementContext ctx) {
-    parseGroupByLevelClause(ctx.groupByLevelClause(), queryOp);
+    queryOp = new AggregationQueryOperator();
+    parseGroupByLevelClause(ctx.groupByLevelClause());
     if (ctx.orderByTimeClause() != null) {
-      parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp);
+      parseOrderByTimeClause(ctx.orderByTimeClause());
     }
     if (ctx.specialLimit() != null) {
       return visit(ctx.specialLimit());
@@ -1218,15 +1262,14 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     return queryOp;
   }
 
-  @Override
-  public Operator visitFromClause(FromClauseContext ctx) {
-    FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
+  public void parseFromClause(FromClauseContext ctx) {
+    FromComponent fromComponent = new FromComponent();
     List<PrefixPathContext> prefixFromPaths = ctx.prefixPath();
     for (PrefixPathContext prefixFromPath : prefixFromPaths) {
       PartialPath path = parsePrefixPath(prefixFromPath);
-      fromOp.addPrefixTablePath(path);
+      fromComponent.addPrefixTablePath(path);
     }
-    return fromOp;
+    queryOp.setFromComponent(fromComponent);
   }
 
   private void parseIndexPredicate(IndexPredicateClauseContext ctx) {
@@ -1239,11 +1282,11 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     }
     if (ctx.LIKE() != null) {
       // whole matching case
-      if (queryOp.getSelectOperator().getResultColumns().size() != 1) {
+      if (queryOp.getSelectComponent().getResultColumns().size() != 1) {
         throw new SQLParserException("Index query statement allows only one select path");
       }
       if (!path.equals(
-          queryOp.getSelectOperator().getResultColumns().get(0).getExpression().toString())) {
+          queryOp.getSelectComponent().getResultColumns().get(0).getExpression().toString())) {
         throw new SQLParserException(
             "In the index query statement, "
                 + "the path in select element and the index predicate should be same");
@@ -1270,7 +1313,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
       }
       List<ResultColumn> resultColumns = new ArrayList<>();
       resultColumns.add(new ResultColumn(new TimeSeriesOperand(path)));
-      queryOp.getSelectOperator().setResultColumns(resultColumns);
+      queryOp.getSelectComponent().setResultColumns(resultColumns);
       props.put(PATTERN, compositePattern);
       props.put(THRESHOLD, thresholds);
       queryOp.setIndexType(IndexType.ELB_INDEX);
@@ -1289,26 +1332,28 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     return sequence;
   }
 
-  public void parseGroupByLevelClause(GroupByLevelClauseContext ctx, QueryOperator queryOp) {
-    if (!queryOp.hasAggregationFunction()) {
+  public void parseGroupByLevelClause(GroupByLevelClauseContext ctx) {
+    /*    if (!queryOp.hasAggregationFunction()) {
       throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE);
-    }
-    queryOp.setGroupByLevel(true);
-    queryOp.setLevel(Integer.parseInt(ctx.INT().getText()));
+    }*/
+    GroupByLevelClauseComponent groupByLevelClauseComponent = new GroupByLevelClauseComponent();
+    groupByLevelClauseComponent.setLevel(Integer.parseInt(ctx.INT().getText()));
+    queryOp.setSpecialClauseComponent(groupByLevelClauseComponent);
   }
 
-  public void parseFillClause(FillClauseContext ctx, QueryOperator queryOp) {
-    FilterOperator filterOperator = queryOp.getFilterOperator();
+  public void parseFillClause(FillClauseContext ctx) {
+    /*    FilterOperator filterOperator = queryOp.getFilterOperator();
     if (!filterOperator.isLeaf() || filterOperator.getTokenIntType() != SQLConstant.EQUAL) {
       throw new SQLParserException("Only \"=\" can be used in fill function");
-    }
+    }*/
+    FillClauseComponent fillClauseComponent = new FillClauseComponent();
     List<TypeClauseContext> list = ctx.typeClause();
     Map<TSDataType, IFill> fillTypes = new EnumMap<>(TSDataType.class);
     for (TypeClauseContext typeClause : list) {
       parseTypeClause(typeClause, fillTypes);
     }
-    queryOp.setFill(true);
-    queryOp.setFillTypes(fillTypes);
+    fillClauseComponent.setFillTypes(fillTypes);
+    queryOp.setSpecialClauseComponent(fillClauseComponent);
   }
 
   private void parseLimitClause(LimitClauseContext ctx, Operator operator) {
@@ -1326,7 +1371,12 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     } else if (operator instanceof ShowDevicesOperator) {
       ((ShowDevicesOperator) operator).setLimit(limit);
     } else {
-      ((QueryOperator) operator).setRowLimit(limit);
+      SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+      if (specialClauseComponent == null) {
+        specialClauseComponent = new SpecialClauseComponent();
+      }
+      specialClauseComponent.setRowLimit(limit);
+      queryOp.setSpecialClauseComponent(specialClauseComponent);
     }
     if (ctx.offsetClause() != null) {
       parseOffsetClause(ctx.offsetClause(), operator);
@@ -1349,11 +1399,16 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     } else if (operator instanceof ShowDevicesOperator) {
       ((ShowDevicesOperator) operator).setOffset(offset);
     } else {
-      ((QueryOperator) operator).setRowOffset(offset);
+      SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+      if (specialClauseComponent == null) {
+        specialClauseComponent = new SpecialClauseComponent();
+      }
+      specialClauseComponent.setRowOffset(offset);
+      queryOp.setSpecialClauseComponent(specialClauseComponent);
     }
   }
 
-  private void parseSlimitClause(SlimitClauseContext ctx, QueryOperator queryOp) {
+  private void parseSlimitClause(SlimitClauseContext ctx) {
     int slimit;
     try {
       slimit = Integer.parseInt(ctx.INT().getText());
@@ -1363,7 +1418,12 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     if (slimit <= 0) {
       throw new SQLParserException("SLIMIT <SN>: SN should be greater than 0.");
     }
-    queryOp.setSeriesLimit(slimit);
+    SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+    if (specialClauseComponent == null) {
+      specialClauseComponent = new SpecialClauseComponent();
+    }
+    specialClauseComponent.setSeriesLimit(slimit);
+    queryOp.setSpecialClauseComponent(specialClauseComponent);
     if (ctx.soffsetClause() != null) {
       parseSoffsetClause(ctx.soffsetClause(), queryOp);
     }
@@ -1380,50 +1440,57 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     if (soffset < 0) {
       throw new SQLParserException("SOFFSET <SOFFSETValue>: SOFFSETValue should >= 0.");
     }
-    queryOp.setSeriesOffset(soffset);
+    SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+    if (specialClauseComponent == null) {
+      specialClauseComponent = new SpecialClauseComponent();
+    }
+    specialClauseComponent.setSeriesOffset(soffset);
+    queryOp.setSpecialClauseComponent(specialClauseComponent);
   }
 
-  private void parseGroupByTimeClause(GroupByTimeClauseContext ctx, QueryOperator queryOp) {
-    if (!queryOp.hasAggregationFunction()) {
+  private void parseGroupByTimeClause(GroupByTimeClauseContext ctx) {
+    /*    if (!queryOp.hasAggregationFunction()) {
       throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE);
-    }
-    queryOp.setGroupByTime(true);
-    queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
+    }*/
+    GroupByClauseComponent groupByClauseComponent = new GroupByClauseComponent();
+    groupByClauseComponent.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
     // parse timeUnit
-    queryOp.setUnit(parseTimeUnitOrSlidingStep(queryOp, ctx.DURATION(0).getText(), true));
+    groupByClauseComponent.setUnit(
+        parseTimeUnitOrSlidingStep(ctx.DURATION(0).getText(), true, groupByClauseComponent));
     // parse sliding step
     if (ctx.DURATION().size() == 2) {
-      queryOp.setSlidingStep(parseTimeUnitOrSlidingStep(queryOp, ctx.DURATION(1).getText(), false));
-      if (queryOp.getSlidingStep() < queryOp.getUnit()) {
+      groupByClauseComponent.setSlidingStep(
+          parseTimeUnitOrSlidingStep(ctx.DURATION(1).getText(), false, groupByClauseComponent));
+      if (groupByClauseComponent.getSlidingStep() < groupByClauseComponent.getUnit()) {
         throw new SQLParserException(
             "The third parameter sliding step shouldn't be smaller than the second parameter time interval.");
       }
     } else {
-      queryOp.setSlidingStep(queryOp.getUnit());
-      queryOp.setSlidingStepByMonth(queryOp.isIntervalByMonth());
+      groupByClauseComponent.setSlidingStep(groupByClauseComponent.getUnit());
+      groupByClauseComponent.setSlidingStepByMonth(groupByClauseComponent.isIntervalByMonth());
     }
 
-    parseTimeInterval(ctx.timeInterval(), queryOp);
+    parseTimeInterval(ctx.timeInterval(), groupByClauseComponent);
 
     if (ctx.INT() != null) {
-      queryOp.setGroupByLevel(true);
-      queryOp.setLevel(Integer.parseInt(ctx.INT().getText()));
+      groupByClauseComponent.setLevel(Integer.parseInt(ctx.INT().getText()));
     }
+    queryOp.setSpecialClauseComponent(groupByClauseComponent);
   }
 
-  private void parseGroupByFillClause(GroupByFillClauseContext ctx, QueryOperator queryOp) {
-    if (!queryOp.hasAggregationFunction()) {
+  private void parseGroupByFillClause(GroupByFillClauseContext ctx) {
+    /*    if (!queryOp.hasAggregationFunction()) {
       throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE);
-    }
-    queryOp.setGroupByTime(true);
-    queryOp.setFill(true);
-    queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
+    }*/
+    GroupByFillClauseComponent groupByFillClauseComponent = new GroupByFillClauseComponent();
+    groupByFillClauseComponent.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
 
     // parse timeUnit
-    queryOp.setUnit(DatetimeUtils.convertDurationStrToLong(ctx.DURATION().getText()));
-    queryOp.setSlidingStep(queryOp.getUnit());
+    groupByFillClauseComponent.setUnit(
+        DatetimeUtils.convertDurationStrToLong(ctx.DURATION().getText()));
+    groupByFillClauseComponent.setSlidingStep(groupByFillClauseComponent.getUnit());
 
-    parseTimeInterval(ctx.timeInterval(), queryOp);
+    parseTimeInterval(ctx.timeInterval(), groupByFillClauseComponent);
 
     List<TypeClauseContext> list = ctx.typeClause();
     Map<TSDataType, IFill> fillTypes = new EnumMap<>(TSDataType.class);
@@ -1464,8 +1531,8 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
         parseTypeClause(typeClause, fillTypes);
       }
     }
-    queryOp.setFill(true);
-    queryOp.setFillTypes(fillTypes);
+    groupByFillClauseComponent.setFillTypes(fillTypes);
+    queryOp.setSpecialClauseComponent(groupByFillClauseComponent);
   }
 
   private void parseTypeClause(TypeClauseContext ctx, Map<TSDataType, IFill> fillTypes) {
@@ -1530,22 +1597,27 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     }
   }
 
-  private void parseOrderByTimeClause(OrderByTimeClauseContext ctx, QueryOperator queryOp) {
-    queryOp.setColumn(ctx.TIME().getText());
+  private void parseOrderByTimeClause(OrderByTimeClauseContext ctx) {
     if (ctx.DESC() != null) {
-      queryOp.setAscending(false);
+      SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent();
+      if (specialClauseComponent == null) {
+        specialClauseComponent = new SpecialClauseComponent();
+      }
+      specialClauseComponent.setAscending(false);
+      queryOp.setSpecialClauseComponent(specialClauseComponent);
     }
   }
 
-  private void parseAlignByDeviceClause(QueryOperator queryOp) {
-    queryOp.setAlignByDevice(true);
+  private void parseAlignByDeviceClause(SpecialClauseComponent specialClauseComponent) {
+    specialClauseComponent.setAlignByDevice(true);
   }
 
-  private void parseDisableAlign(QueryOperator queryOp) {
-    queryOp.setAlignByTime(false);
+  private void parseDisableAlign(SpecialClauseComponent specialClauseComponent) {
+    specialClauseComponent.setAlignByTime(false);
   }
 
-  private void parseTimeInterval(TimeIntervalContext timeInterval, QueryOperator queryOp) {
+  private void parseTimeInterval(
+      TimeIntervalContext timeInterval, GroupByClauseComponent groupByClauseComponent) {
     long startTime;
     long endTime;
     if (timeInterval.timeValue(0).INT() != null) {
@@ -1563,10 +1635,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
       endTime = parseTimeFormat(timeInterval.timeValue(1).dateFormat().getText());
     }
 
-    queryOp.setStartTime(startTime);
-    queryOp.setEndTime(endTime);
+    groupByClauseComponent.setStartTime(startTime);
+    groupByClauseComponent.setEndTime(endTime);
     if (startTime >= endTime) {
-      throw new SQLParserException("start time should be smaller than endTime in GroupBy");
+      throw new SQLParserException("Start time should be smaller than endTime in GroupBy");
     }
   }
 
@@ -1793,12 +1865,12 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
    * @return time in milliseconds, microseconds, or nanoseconds depending on the profile
    */
   private long parseTimeUnitOrSlidingStep(
-      QueryOperator queryOp, String durationStr, boolean isParsingTimeUnit) {
+      String durationStr, boolean isParsingTimeUnit, GroupByClauseComponent groupByComponent) {
     if (durationStr.toLowerCase().contains("mo")) {
       if (isParsingTimeUnit) {
-        queryOp.setIntervalByMonth(true);
+        groupByComponent.setIntervalByMonth(true);
       } else {
-        queryOp.setSlidingStepByMonth(true);
+        groupByComponent.setSlidingStepByMonth(true);
       }
     }
     return DatetimeUtils.convertDurationStrToLong(durationStr);
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java
index f55fe7c..b5b0d2a 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java
@@ -22,8 +22,9 @@ package org.apache.iotdb.db.qp.strategy;
 import org.apache.iotdb.db.exception.query.LogicalOperatorException;
 import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
 import org.apache.iotdb.db.query.expression.Expression;
 import org.apache.iotdb.db.query.expression.ResultColumn;
 import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
@@ -53,12 +54,12 @@ public class LogicalChecker {
   }
 
   private static void checkLast(QueryOperator queryOperator) throws LogicalOperatorException {
-    SelectOperator selectOperator = queryOperator.getSelectOperator();
-    if (!selectOperator.isLastQuery()) {
+    SelectComponent selectComponent = queryOperator.getSelectComponent();
+    if (!(queryOperator instanceof LastQueryOperator)) {
       return;
     }
 
-    for (ResultColumn resultColumn : selectOperator.getResultColumns()) {
+    for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
       Expression expression = resultColumn.getExpression();
       if (!(expression instanceof TimeSeriesOperand)) {
         throw new LogicalOperatorException("Last queries can only be applied on raw time series.");
@@ -68,12 +69,12 @@ public class LogicalChecker {
 
   private static void checkAggregation(QueryOperator queryOperator)
       throws LogicalOperatorException {
-    SelectOperator selectOperator = queryOperator.getSelectOperator();
-    if (!selectOperator.hasAggregationFunction()) {
+    SelectComponent selectComponent = queryOperator.getSelectComponent();
+    if (!selectComponent.hasAggregationFunction()) {
       return;
     }
 
-    for (ResultColumn resultColumn : selectOperator.getResultColumns()) {
+    for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
       Expression expression = resultColumn.getExpression();
       if (expression instanceof TimeSeriesOperand) {
         throw new LogicalOperatorException(
@@ -88,12 +89,12 @@ public class LogicalChecker {
       return;
     }
 
-    SelectOperator selectOperator = queryOperator.getSelectOperator();
-    if (selectOperator.hasTimeSeriesGeneratingFunction()) {
+    SelectComponent selectComponent = queryOperator.getSelectComponent();
+    if (selectComponent.hasTimeSeriesGeneratingFunction()) {
       throw new LogicalOperatorException("ALIGN BY DEVICE clause is not supported in UDF queries.");
     }
 
-    for (PartialPath path : selectOperator.getPaths()) {
+    for (PartialPath path : selectComponent.getPaths()) {
       String device = path.getDevice();
       if (!device.isEmpty()) {
         throw new LogicalOperatorException(
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index 51a5e72..7b216d8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -24,9 +24,9 @@ import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
-import org.apache.iotdb.db.qp.logical.crud.FromOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromComponent;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
 import org.apache.iotdb.db.qp.sql.IoTDBSqlVisitor;
 import org.apache.iotdb.db.qp.sql.SqlBaseLexer;
 import org.apache.iotdb.db.qp.sql.SqlBaseParser;
@@ -84,9 +84,9 @@ public class LogicalGenerator {
   public static Operator generate(TSRawDataQueryReq rawDataQueryReq, ZoneId zoneId)
       throws IllegalPathException {
     // construct query operator and set its global time filter
-    QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
-    FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
-    SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId);
+    QueryOperator queryOp = new QueryOperator();
+    FromComponent fromOp = new FromComponent();
+    SelectComponent selectOp = new SelectComponent(zoneId);
 
     // iterate the path list and add it to from operator
     for (String p : rawDataQueryReq.getPaths()) {
@@ -95,8 +95,8 @@ public class LogicalGenerator {
     }
     selectOp.addResultColumn(new ResultColumn(new TimeSeriesOperand(new PartialPath(""))));
 
-    queryOp.setSelectOperator(selectOp);
-    queryOp.setFromOperator(fromOp);
+    queryOp.setSelectComponent(selectOp);
+    queryOp.setFromComponent(fromOp);
 
     // set time filter operator
     FilterOperator filterOp = new FilterOperator(SQLConstant.KW_AND);
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
index 5c81c6e..223e8fa 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
@@ -30,9 +30,17 @@ import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
 import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator;
+import org.apache.iotdb.db.qp.logical.crud.FillClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.FillQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
+import org.apache.iotdb.db.qp.logical.crud.GroupByClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByFillClauseComponent;
+import org.apache.iotdb.db.qp.logical.crud.GroupByFillQueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.GroupByQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.InsertOperator;
+import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.SpecialClauseComponent;
 import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator;
 import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
 import org.apache.iotdb.db.qp.logical.sys.CountOperator;
@@ -471,41 +479,45 @@ public class PhysicalGenerator {
         throw new QueryProcessException(
             "User-defined and built-in hybrid aggregation is not supported.");
       }
-      if (queryOperator.isGroupByTime() && queryOperator.isFill()) {
+      if (queryOperator instanceof GroupByFillQueryOperator) {
         queryPlan = new GroupByTimeFillPlan();
-      } else if (queryOperator.isGroupByTime()) {
+      } else if (queryOperator instanceof GroupByQueryOperator) {
         queryPlan = new GroupByTimePlan();
       } else {
         queryPlan = new AggregationPlan();
       }
 
-      queryPlan.setPaths(queryOperator.getSelectOperator().getPaths());
-      queryPlan.setAggregations(queryOperator.getSelectOperator().getAggregationFunctions());
+      queryPlan.setPaths(queryOperator.getSelectComponent().getPaths());
+      queryPlan.setAggregations(queryOperator.getSelectComponent().getAggregationFunctions());
 
-      if (queryOperator.isGroupByTime()) {
+      if (queryOperator instanceof GroupByQueryOperator) {
         GroupByTimePlan groupByTimePlan = (GroupByTimePlan) queryPlan;
-        groupByTimePlan.setInterval(queryOperator.getUnit());
-        groupByTimePlan.setIntervalByMonth(queryOperator.isIntervalByMonth());
-        groupByTimePlan.setSlidingStep(queryOperator.getSlidingStep());
-        groupByTimePlan.setSlidingStepByMonth(queryOperator.isSlidingStepByMonth());
-        groupByTimePlan.setLeftCRightO(queryOperator.isLeftCRightO());
-        if (!queryOperator.isLeftCRightO()) {
-          groupByTimePlan.setStartTime(queryOperator.getStartTime() + 1);
-          groupByTimePlan.setEndTime(queryOperator.getEndTime() + 1);
+        GroupByClauseComponent groupByClauseComponent =
+            (GroupByClauseComponent) queryOperator.getSpecialClauseComponent();
+        groupByTimePlan.setInterval(groupByClauseComponent.getUnit());
+        groupByTimePlan.setIntervalByMonth(groupByClauseComponent.isIntervalByMonth());
+        groupByTimePlan.setSlidingStep(groupByClauseComponent.getSlidingStep());
+        groupByTimePlan.setSlidingStepByMonth(groupByClauseComponent.isSlidingStepByMonth());
+        groupByTimePlan.setLeftCRightO(groupByClauseComponent.isLeftCRightO());
+        if (!groupByClauseComponent.isLeftCRightO()) {
+          groupByTimePlan.setStartTime(groupByClauseComponent.getStartTime() + 1);
+          groupByTimePlan.setEndTime(groupByClauseComponent.getEndTime() + 1);
         } else {
-          groupByTimePlan.setStartTime(queryOperator.getStartTime());
-          groupByTimePlan.setEndTime(queryOperator.getEndTime());
+          groupByTimePlan.setStartTime(groupByClauseComponent.getStartTime());
+          groupByTimePlan.setEndTime(groupByClauseComponent.getEndTime());
         }
       }
-      if (queryOperator.isFill()) {
-        ((GroupByTimeFillPlan) queryPlan).setFillType(queryOperator.getFillTypes());
+      if (queryOperator instanceof GroupByFillQueryOperator) {
+        GroupByFillClauseComponent groupByFillClauseComponent =
+            (GroupByFillClauseComponent) queryOperator.getSpecialClauseComponent();
+        ((GroupByTimeFillPlan) queryPlan).setFillType(groupByFillClauseComponent.getFillTypes());
         for (String aggregation : queryPlan.getAggregations()) {
           if (!SQLConstant.LAST_VALUE.equals(aggregation)) {
             throw new QueryProcessException("Group By Fill only support last_value function");
           }
         }
       } else if (queryOperator.isGroupByLevel()) {
-        queryPlan.setLevel(queryOperator.getLevel());
+        queryPlan.setLevel(queryOperator.getSpecialClauseComponent().getLevel());
         try {
           if (!verifyAllAggregationDataTypesEqual(queryOperator)) {
             throw new QueryProcessException("Aggregate among unmatched data types");
@@ -523,17 +535,19 @@ public class PhysicalGenerator {
 
     @Override
     public QueryPlan transform(QueryOperator queryOperator) throws QueryProcessException {
+      FillQueryOperator fillQueryOperator = (FillQueryOperator) queryOperator;
       if (queryOperator.hasTimeSeriesGeneratingFunction()) {
         throw new QueryProcessException("Fill functions are not supported in UDF queries.");
       }
       FillQueryPlan queryPlan = new FillQueryPlan();
-      FilterOperator timeFilter = queryOperator.getFilterOperator();
+      FilterOperator timeFilter = fillQueryOperator.getFilterOperator();
       if (!timeFilter.isSingle()) {
         throw new QueryProcessException("Slice query must select a single time point");
       }
       long time = Long.parseLong(((BasicFunctionOperator) timeFilter).getValue());
       queryPlan.setQueryTime(time);
-      queryPlan.setFillType(queryOperator.getFillTypes());
+      queryPlan.setFillType(
+          ((FillClauseComponent) fillQueryOperator.getSpecialClauseComponent()).getFillTypes());
       return queryPlan;
     }
   }
@@ -544,24 +558,25 @@ public class PhysicalGenerator {
 
     if (queryOperator.hasAggregationFunction()) {
       queryPlan = new AggPhysicalPlanRule().transform(queryOperator);
-    } else if (queryOperator.isFill()) {
+    } else if (queryOperator instanceof FillQueryOperator) {
       queryPlan = new FillPhysicalPlanRule().transform(queryOperator);
-    } else if (queryOperator.isLastQuery()) {
+    } else if (queryOperator instanceof LastQueryOperator) {
       queryPlan = new LastQueryPlan();
     } else if (queryOperator.getIndexType() != null) {
       queryPlan = new QueryIndexPlan();
     } else if (queryOperator.hasTimeSeriesGeneratingFunction()) {
-      queryPlan = new UDTFPlan(queryOperator.getSelectOperator().getZoneId());
+      queryPlan = new UDTFPlan(queryOperator.getSelectComponent().getZoneId());
       ((UDTFPlan) queryPlan)
-          .constructUdfExecutors(queryOperator.getSelectOperator().getResultColumns());
+          .constructUdfExecutors(queryOperator.getSelectComponent().getResultColumns());
     } else {
       queryPlan = new RawDataQueryPlan();
     }
 
-    if (queryOperator.isAlignByDevice()) {
+    if (queryOperator.getSpecialClauseComponent() != null
+        && queryOperator.getSpecialClauseComponent().isAlignByDevice()) {
       queryPlan = getAlignQueryPlan(queryOperator, queryPlan);
     } else {
-      queryPlan.setPaths(queryOperator.getSelectOperator().getPaths());
+      queryPlan.setPaths(queryOperator.getSelectComponent().getPaths());
       // Last query result set will not be affected by alignment
       if (queryPlan instanceof LastQueryPlan && !queryOperator.isAlignByTime()) {
         throw new QueryProcessException("Disable align cannot be applied to LAST query.");
@@ -588,9 +603,6 @@ public class PhysicalGenerator {
       }
     }
 
-    queryPlan.setWithoutAllNull(queryOperator.isWithoutAllNull());
-    queryPlan.setWithoutAnyNull(queryOperator.isWithoutAnyNull());
-
     if (queryOperator.getIndexType() != null) {
       if (queryPlan instanceof QueryIndexPlan) {
         ((QueryIndexPlan) queryPlan).setIndexType(queryOperator.getIndexType());
@@ -599,7 +611,7 @@ public class PhysicalGenerator {
       return queryPlan;
     }
 
-    queryPlan.setResultColumns(queryOperator.getSelectOperator().getResultColumns());
+    queryPlan.setResultColumns(queryOperator.getSelectComponent().getResultColumns());
 
     try {
       List<PartialPath> paths = queryPlan.getPaths();
@@ -611,9 +623,14 @@ public class PhysicalGenerator {
       throw new QueryProcessException(e);
     }
 
-    queryPlan.setRowLimit(queryOperator.getRowLimit());
-    queryPlan.setRowOffset(queryOperator.getRowOffset());
-    queryPlan.setAscending(queryOperator.isAscending());
+    if (queryOperator.getSpecialClauseComponent() != null) {
+      SpecialClauseComponent specialClauseComponent = queryOperator.getSpecialClauseComponent();
+      queryPlan.setWithoutAllNull(specialClauseComponent.isWithoutAllNull());
+      queryPlan.setWithoutAnyNull(specialClauseComponent.isWithoutAnyNull());
+      queryPlan.setRowLimit(specialClauseComponent.getRowLimit());
+      queryPlan.setRowOffset(specialClauseComponent.getRowOffset());
+      queryPlan.setAscending(specialClauseComponent.isAscending());
+    }
 
     return queryPlan;
   }
@@ -634,11 +651,11 @@ public class PhysicalGenerator {
       alignByDevicePlan.setAggregationPlan((AggregationPlan) queryPlan);
     }
 
-    List<PartialPath> prefixPaths = queryOperator.getFromOperator().getPrefixPaths();
+    List<PartialPath> prefixPaths = queryOperator.getFromComponent().getPrefixPaths();
     // remove stars in fromPaths and get deviceId with deduplication
     List<PartialPath> devices = this.removeStarsInDeviceWithUnique(prefixPaths);
-    List<ResultColumn> resultColumns = queryOperator.getSelectOperator().getResultColumns();
-    List<String> originAggregations = queryOperator.getSelectOperator().getAggregationFunctions();
+    List<ResultColumn> resultColumns = queryOperator.getSelectComponent().getResultColumns();
+    List<String> originAggregations = queryOperator.getSelectComponent().getAggregationFunctions();
 
     // to record result measurement columns
     List<String> measurements = new ArrayList<>();
@@ -771,9 +788,9 @@ public class PhysicalGenerator {
     }
 
     // slimit trim on the measurementColumnList
-    if (queryOperator.hasSlimit()) {
-      int seriesSlimit = queryOperator.getSeriesLimit();
-      int seriesOffset = queryOperator.getSeriesOffset();
+    if (queryOperator.getSpecialClauseComponent().hasSlimit()) {
+      int seriesSlimit = queryOperator.getSpecialClauseComponent().getSeriesLimit();
+      int seriesOffset = queryOperator.getSpecialClauseComponent().getSeriesOffset();
       measurements = slimitTrimColumn(measurements, seriesSlimit, seriesOffset);
     }
 
@@ -890,12 +907,12 @@ public class PhysicalGenerator {
 
   private static boolean verifyAllAggregationDataTypesEqual(QueryOperator queryOperator)
       throws MetadataException {
-    List<String> aggregations = queryOperator.getSelectOperator().getAggregationFunctions();
+    List<String> aggregations = queryOperator.getSelectComponent().getAggregationFunctions();
     if (aggregations.isEmpty()) {
       return true;
     }
 
-    List<PartialPath> paths = queryOperator.getSelectOperator().getPaths();
+    List<PartialPath> paths = queryOperator.getSelectComponent().getPaths();
     List<TSDataType> dataTypes = SchemaUtils.getSeriesTypesByPaths(paths);
     String aggType = aggregations.get(0);
     switch (aggType) {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
index 89db221..f8b3eb8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
@@ -27,10 +27,11 @@ import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
-import org.apache.iotdb.db.qp.logical.crud.FromOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromComponent;
 import org.apache.iotdb.db.qp.logical.crud.FunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
 import org.apache.iotdb.db.qp.utils.WildcardsRemover;
 import org.apache.iotdb.db.query.expression.ResultColumn;
 import org.apache.iotdb.db.service.IoTDB;
@@ -68,13 +69,13 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
   }
 
   private static boolean optimizable(QueryOperator queryOperator) {
-    FromOperator from = queryOperator.getFromOperator();
+    FromComponent from = queryOperator.getFromComponent();
     if (from == null || from.getPrefixPaths().isEmpty()) {
       LOGGER.warn(WARNING_NO_PREFIX_PATHS);
       return false;
     }
 
-    SelectOperator select = queryOperator.getSelectOperator();
+    SelectComponent select = queryOperator.getSelectComponent();
     if (select == null || select.getResultColumns().isEmpty()) {
       LOGGER.warn(WARNING_NO_SUFFIX_PATHS);
       return false;
@@ -84,35 +85,35 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
   }
 
   private void concatSelect(QueryOperator queryOperator) throws LogicalOptimizeException {
-    if (queryOperator.isAlignByDevice() && !queryOperator.isLastQuery()) {
+    if (queryOperator.isAlignByDevice() && !(queryOperator instanceof LastQueryOperator)) {
       return;
     }
 
-    List<PartialPath> prefixPaths = queryOperator.getFromOperator().getPrefixPaths();
+    List<PartialPath> prefixPaths = queryOperator.getFromComponent().getPrefixPaths();
     List<ResultColumn> resultColumns = new ArrayList<>();
-    for (ResultColumn suffixColumn : queryOperator.getSelectOperator().getResultColumns()) {
+    for (ResultColumn suffixColumn : queryOperator.getSelectComponent().getResultColumns()) {
       suffixColumn.concat(prefixPaths, resultColumns);
     }
-    queryOperator.getSelectOperator().setResultColumns(resultColumns);
+    queryOperator.getSelectComponent().setResultColumns(resultColumns);
   }
 
   private void removeWildcardsInSelectPaths(QueryOperator queryOperator, int fetchSize)
       throws LogicalOptimizeException, PathNumOverLimitException {
-    if (queryOperator.isAlignByDevice() && !queryOperator.isLastQuery()
+    if (queryOperator.isAlignByDevice() && !(queryOperator instanceof LastQueryOperator)
         || queryOperator.getIndexType() != null) {
       return;
     }
 
     WildcardsRemover wildcardsRemover = new WildcardsRemover(this, queryOperator, fetchSize);
     List<ResultColumn> resultColumns = new ArrayList<>();
-    for (ResultColumn resultColumn : queryOperator.getSelectOperator().getResultColumns()) {
+    for (ResultColumn resultColumn : queryOperator.getSelectComponent().getResultColumns()) {
       resultColumn.removeWildcards(wildcardsRemover, resultColumns);
       if (wildcardsRemover.checkIfPathNumberIsOverLimit(resultColumns)) {
         break;
       }
     }
     wildcardsRemover.checkIfSoffsetIsExceeded(resultColumns);
-    queryOperator.getSelectOperator().setResultColumns(resultColumns);
+    queryOperator.getSelectComponent().setResultColumns(resultColumns);
   }
 
   private void concatFilter(QueryOperator queryOperator) throws LogicalOptimizeException {
@@ -122,11 +123,11 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
     }
 
     Set<PartialPath> filterPaths = new HashSet<>();
-    if (!queryOperator.isAlignByDevice() || queryOperator.isLastQuery()) {
+    if (!queryOperator.isAlignByDevice() || queryOperator instanceof LastQueryOperator) {
       // GROUP_BY_DEVICE leaves the concatFilter to PhysicalGenerator to optimize filter without
       // prefix first
       queryOperator.setFilterOperator(
-          concatFilter(queryOperator.getFromOperator().getPrefixPaths(), filter, filterPaths));
+          concatFilter(queryOperator.getFromComponent().getPrefixPaths(), filter, filterPaths));
     }
     queryOperator.getFilterOperator().setPathSet(filterPaths);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
index d2e6054..d841f0e 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
 import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
 import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
 import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
 import org.apache.iotdb.db.query.control.QueryResourceManager;
@@ -39,11 +40,11 @@ public class WildcardsRemover {
   private final ConcatPathOptimizer concatPathOptimizer;
 
   private final int maxDeduplicatedPathNum;
-  private final int soffset;
+  private int soffset = 0;
 
-  private int offset;
-  private int limit;
-  private int consumed;
+  private int offset = 0;
+  private int limit = Integer.MAX_VALUE;
+  private int consumed = 0;
 
   public WildcardsRemover(
       ConcatPathOptimizer concatPathOptimizer, QueryOperator queryOperator, int fetchSize) {
@@ -54,25 +55,21 @@ public class WildcardsRemover {
     // To avoid overflowing because logicalOptimize function may do maxDeduplicatedPathNum + 1, we
     // set it to Integer.MAX_VALUE - 1
     maxDeduplicatedPathNum =
-        queryOperator.isLastQuery()
+        queryOperator instanceof LastQueryOperator
             ? Integer.MAX_VALUE - 1
             : QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(fetchSize);
-    soffset = queryOperator.getSeriesOffset();
-    offset = soffset;
+    if (queryOperator.getSpecialClauseComponent() != null) {
+      soffset = queryOperator.getSpecialClauseComponent().getSeriesOffset();
+      offset = soffset;
 
-    final int slimit = queryOperator.getSeriesLimit();
-    limit = slimit == 0 || maxDeduplicatedPathNum < slimit ? maxDeduplicatedPathNum + 1 : slimit;
-
-    consumed = 0;
+      final int slimit = queryOperator.getSpecialClauseComponent().getSeriesLimit();
+      limit = slimit == 0 || maxDeduplicatedPathNum < slimit ? maxDeduplicatedPathNum + 1 : slimit;
+    }
   }
 
   public WildcardsRemover(ConcatPathOptimizer concatPathOptimizer) {
     this.concatPathOptimizer = concatPathOptimizer;
-
     maxDeduplicatedPathNum = Integer.MAX_VALUE - 1;
-    soffset = 0;
-    limit = maxDeduplicatedPathNum + 1;
-    consumed = 0;
   }
 
   public List<PartialPath> removeWildcardFrom(PartialPath path) throws LogicalOptimizeException {
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
index a1c06bb..0db57f3 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
@@ -526,7 +526,7 @@ public class IoTDBGroupByFillIT {
       hasResultSet =
           statement.execute(
               "select last_value(temperature) from root.ln.wf01.wt01 "
-                  + "GROUP BY ([2, 48), 5ms) FILL(int32[previousUntilLast])order by time desc");
+                  + "GROUP BY ([2, 48), 5ms) FILL(int32[previousUntilLast]) order by time desc");
 
       assertTrue(hasResultSet);
       try (ResultSet resultSet = statement.getResultSet()) {
diff --git a/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java b/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java
index 38593cb..c8515d2 100644
--- a/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java
@@ -108,9 +108,9 @@ public class IndexLogicalPlanTest {
     Assert.assertEquals(OperatorType.QUERY, queryOperator.getType());
     Assert.assertEquals(
         "Glu",
-        queryOperator.getSelectOperator().getResultColumns().get(0).getExpression().toString());
+        queryOperator.getSelectComponent().getResultColumns().get(0).getExpression().toString());
     Assert.assertEquals(
-        "root.Ery.*", queryOperator.getFromOperator().getPrefixPaths().get(0).getFullPath());
+        "root.Ery.*", queryOperator.getFromComponent().getPrefixPaths().get(0).getFullPath());
     Assert.assertEquals(IndexType.RTREE_PAA, queryOperator.getIndexType());
     Assert.assertEquals(2, queryOperator.getProps().size());
     Assert.assertEquals(2, (int) queryOperator.getProps().get(TOP_K));
@@ -132,9 +132,9 @@ public class IndexLogicalPlanTest {
     Assert.assertEquals(OperatorType.QUERY, queryOperator.getType());
     Assert.assertEquals(
         "Speed",
-        queryOperator.getSelectOperator().getResultColumns().get(0).getExpression().toString());
+        queryOperator.getSelectComponent().getResultColumns().get(0).getExpression().toString());
     Assert.assertEquals(
-        "root.Wind.AZQ02", queryOperator.getFromOperator().getPrefixPaths().get(0).getFullPath());
+        "root.Wind.AZQ02", queryOperator.getFromComponent().getPrefixPaths().get(0).getFullPath());
     Assert.assertEquals(IndexType.ELB_INDEX, queryOperator.getIndexType());
     Assert.assertEquals(2, queryOperator.getProps().size());
     Assert.assertEquals("[1.0, 2.0, 1.0]", queryOperator.getProps().get(THRESHOLD).toString());
diff --git a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
index d2e428d..77110f2 100644
--- a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
@@ -43,63 +43,63 @@ public class LogicalPlanSmallTest {
   @Test
   public void testLimit() {
     String sqlStr = "select * from root.vehicle.d1 limit 10";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
-    Assert.assertEquals(0, ((QueryOperator) operator).getSeriesLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getSeriesOffset());
+    Assert.assertEquals(10, operator.getSpecialClauseComponent().getRowLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getRowOffset());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getSeriesLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getSeriesOffset());
   }
 
   @Test
   public void testOffset() {
     String sqlStr = "select * from root.vehicle.d1 limit 10 offset 20";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
-    Assert.assertEquals(20, ((QueryOperator) operator).getRowOffset());
-    Assert.assertEquals(0, ((QueryOperator) operator).getSeriesLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getSeriesOffset());
+    Assert.assertEquals(10, operator.getSpecialClauseComponent().getRowLimit());
+    Assert.assertEquals(20, operator.getSpecialClauseComponent().getRowOffset());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getSeriesLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getSeriesOffset());
   }
 
   @Test
   public void testSlimit() {
     String sqlStr = "select * from root.vehicle.d1 limit 10 slimit 1";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
-    Assert.assertEquals(1, ((QueryOperator) operator).getSeriesLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getSeriesOffset());
+    Assert.assertEquals(10, operator.getSpecialClauseComponent().getRowLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getRowOffset());
+    Assert.assertEquals(1, operator.getSpecialClauseComponent().getSeriesLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getSeriesOffset());
   }
 
   @Test
   public void testSOffset() {
     String sqlStr =
         "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 50 slimit 10 soffset 100";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
-    Assert.assertEquals(10, ((QueryOperator) operator).getSeriesLimit());
-    Assert.assertEquals(100, ((QueryOperator) operator).getSeriesOffset());
+    Assert.assertEquals(50, operator.getSpecialClauseComponent().getRowLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getRowOffset());
+    Assert.assertEquals(10, operator.getSpecialClauseComponent().getSeriesLimit());
+    Assert.assertEquals(100, operator.getSpecialClauseComponent().getSeriesOffset());
   }
 
   @Test
   public void testSOffsetTimestamp() {
     String sqlStr =
         "select * from root.vehicle.d1 where s1 < 20 and timestamp <= now() limit 50 slimit 10 soffset 100";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit());
-    Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
-    Assert.assertEquals(10, ((QueryOperator) operator).getSeriesLimit());
-    Assert.assertEquals(100, ((QueryOperator) operator).getSeriesOffset());
+    Assert.assertEquals(50, operator.getSpecialClauseComponent().getRowLimit());
+    Assert.assertEquals(0, operator.getSpecialClauseComponent().getRowOffset());
+    Assert.assertEquals(10, operator.getSpecialClauseComponent().getSeriesLimit());
+    Assert.assertEquals(100, operator.getSpecialClauseComponent().getSeriesOffset());
   }
 
   @Test(expected = SQLParserException.class)
@@ -171,10 +171,10 @@ public class LogicalPlanSmallTest {
   public void testSoffsetNotPositive() {
     String sqlStr =
         "select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 1 soffset 1";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
-    Assert.assertEquals(1, ((QueryOperator) operator).getSeriesOffset());
-    Assert.assertEquals(1, ((QueryOperator) operator).getSeriesLimit());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    Assert.assertEquals(1, operator.getSpecialClauseComponent().getSeriesOffset());
+    Assert.assertEquals(1, operator.getSpecialClauseComponent().getSeriesLimit());
   }
 
   @Test(expected = LogicalOptimizeException.class)
@@ -204,10 +204,10 @@ public class LogicalPlanSmallTest {
   @Test
   public void testDisableAlign() {
     String sqlStr = "select * from root.vehicle disable align";
-    RootOperator operator =
-        (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+    QueryOperator operator =
+        (QueryOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
     Assert.assertEquals(QueryOperator.class, operator.getClass());
-    Assert.assertFalse(((QueryOperator) operator).isAlignByTime());
+    Assert.assertFalse(operator.isAlignByTime());
   }
 
   @Test
@@ -239,7 +239,7 @@ public class LogicalPlanSmallTest {
     Assert.assertEquals(QueryOperator.class, operator.getClass());
     ArrayList<PartialPath> paths = new ArrayList<>();
     paths.add(new PartialPath("*"));
-    Assert.assertEquals(paths, ((QueryOperator) operator).getSelectOperator().getPaths());
+    Assert.assertEquals(paths, ((QueryOperator) operator).getSelectComponent().getPaths());
   }
 
   @Test