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

jackietien pushed a commit to branch ty/TableModelGrammar
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 7ffa882b6fcb0a14870e523bdad10a4e6b7900be
Author: JackieTien97 <[email protected]>
AuthorDate: Thu Apr 18 10:00:49 2024 +0800

    partial ok
---
 .../iotdb/db/protocol/session/IClientSession.java  |  34 +++++-
 .../iotdb/db/protocol/session/SessionManager.java  |   3 +-
 .../iotdb/db/queryengine/common/SessionInfo.java   |  37 +++++-
 .../queryengine/plan/analyze/PredicateUtils.java   |  11 ++
 .../plan/planner/LocalExecutionPlanner.java        |  14 ++-
 .../plan/planner/TableOperatorGenerator.java       | 135 +++++++++++++++------
 .../plan/planner/plan/TableModelTimePredicate.java |  65 ++++++++++
 .../plan/relational/planner/node/LimitNode.java    |   4 +
 .../plan/relational/planner/node/OffsetNode.java   |   4 +
 .../plan/relational/analyzer/AnalyzerTest.java     |   5 +-
 10 files changed, 265 insertions(+), 47 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/IClientSession.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/IClientSession.java
index ff3040a34ec..6ef98c4308a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/IClientSession.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/IClientSession.java
@@ -22,9 +22,13 @@ package org.apache.iotdb.db.protocol.session;
 import org.apache.iotdb.commons.conf.IoTDBConstant.ClientVersion;
 import org.apache.iotdb.service.rpc.thrift.TSConnectionInfo;
 import org.apache.iotdb.service.rpc.thrift.TSConnectionType;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
 import javax.annotation.Nullable;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.time.ZoneId;
 import java.util.Set;
 import java.util.TimeZone;
@@ -159,7 +163,33 @@ public abstract class IClientSession {
   }
 
   public enum SqlDialect {
-    TREE,
-    TABLE
+    TREE((byte) 0),
+    TABLE((byte) 1);
+
+    private final byte dialect;
+
+    SqlDialect(byte dialect) {
+      this.dialect = dialect;
+    }
+
+    public byte getDialect() {
+      return dialect;
+    }
+
+    public void serialize(DataOutputStream stream) throws IOException {
+      ReadWriteIOUtils.write(dialect, stream);
+    }
+
+    public static SqlDialect deserializeFrom(ByteBuffer buffer) {
+      byte b = ReadWriteIOUtils.readByte(buffer);
+      switch (b) {
+        case 0:
+          return TREE;
+        case 1:
+          return TABLE;
+        default:
+          throw new IllegalArgumentException(String.format("Unknown sql 
dialect: %s", b));
+      }
+    }
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
index a3f2c4358ce..6f13111731d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
@@ -378,7 +378,8 @@ public class SessionManager implements SessionManagerMBean {
         session.getUsername(),
         session.getZoneId(),
         session.getClientVersion(),
-        session.getDatabaseName());
+        session.getDatabaseName(),
+        session.getSqlDialect());
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/SessionInfo.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/SessionInfo.java
index 958d39abafa..2cc9aed732a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/SessionInfo.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/SessionInfo.java
@@ -20,7 +20,7 @@
 package org.apache.iotdb.db.queryengine.common;
 
 import org.apache.iotdb.commons.conf.IoTDBConstant.ClientVersion;
-import org.apache.iotdb.commons.utils.TestOnly;
+import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.queryengine.plan.relational.security.Identity;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
@@ -40,6 +40,8 @@ public class SessionInfo {
 
   @Nullable private final String databaseName;
 
+  private final IClientSession.SqlDialect sqlDialect;
+
   private ClientVersion version = ClientVersion.V_1_0;
 
   public SessionInfo(long sessionId, String userName, ZoneId zoneId) {
@@ -47,12 +49,16 @@ public class SessionInfo {
     this.userName = userName;
     this.zoneId = zoneId;
     this.databaseName = null;
+    this.sqlDialect = IClientSession.SqlDialect.TREE;
   }
 
-  @TestOnly
   public SessionInfo(
-      long sessionId, String userName, ZoneId zoneId, @Nullable String 
databaseName) {
-    this(sessionId, userName, zoneId, ClientVersion.V_1_0, databaseName);
+      long sessionId,
+      String userName,
+      ZoneId zoneId,
+      @Nullable String databaseName,
+      IClientSession.SqlDialect sqlDialect) {
+    this(sessionId, userName, zoneId, ClientVersion.V_1_0, databaseName, 
sqlDialect);
   }
 
   public SessionInfo(
@@ -60,12 +66,14 @@ public class SessionInfo {
       String userName,
       ZoneId zoneId,
       ClientVersion version,
-      @Nullable String databaseName) {
+      @Nullable String databaseName,
+      IClientSession.SqlDialect sqlDialect) {
     this.sessionId = sessionId;
     this.userName = userName;
     this.zoneId = zoneId;
     this.version = version;
     this.databaseName = databaseName;
+    this.sqlDialect = sqlDialect;
   }
 
   public long getSessionId() {
@@ -92,16 +100,33 @@ public class SessionInfo {
     return Optional.ofNullable(databaseName);
   }
 
+  public IClientSession.SqlDialect getSqlDialect() {
+    return sqlDialect;
+  }
+
   public static SessionInfo deserializeFrom(ByteBuffer buffer) {
     long sessionId = ReadWriteIOUtils.readLong(buffer);
     String userName = ReadWriteIOUtils.readString(buffer);
     ZoneId zoneId = 
ZoneId.of(Objects.requireNonNull(ReadWriteIOUtils.readString(buffer)));
-    return new SessionInfo(sessionId, userName, zoneId);
+    boolean hasDatabaseName = ReadWriteIOUtils.readBool(buffer);
+    String databaseName = null;
+    if (hasDatabaseName) {
+      databaseName = ReadWriteIOUtils.readString(buffer);
+    }
+    IClientSession.SqlDialect sqlDialect1 = 
IClientSession.SqlDialect.deserializeFrom(buffer);
+    return new SessionInfo(sessionId, userName, zoneId, databaseName, 
sqlDialect1);
   }
 
   public void serialize(DataOutputStream stream) throws IOException {
     ReadWriteIOUtils.write(sessionId, stream);
     ReadWriteIOUtils.write(userName, stream);
     ReadWriteIOUtils.write(zoneId.getId(), stream);
+    if (databaseName == null) {
+      ReadWriteIOUtils.write((byte) 0, stream);
+    } else {
+      ReadWriteIOUtils.write((byte) 1, stream);
+      ReadWriteIOUtils.write(databaseName, stream);
+    }
+    sqlDialect.serialize(stream);
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/PredicateUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/PredicateUtils.java
index dc2d8653b2c..872f80217f9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/PredicateUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/PredicateUtils.java
@@ -279,6 +279,17 @@ public class PredicateUtils {
     return predicate.accept(new ConvertPredicateToTimeFilterVisitor(), null);
   }
 
+  public static Filter convertPredicateToTimeFilter(
+      org.apache.iotdb.db.relational.sql.tree.Expression predicate) {
+    if (predicate == null) {
+      return null;
+    }
+    return predicate.accept(
+        new org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate
+            .ConvertPredicateToTimeFilterVisitor(),
+        null);
+  }
+
   public static Filter convertPredicateToFilter(
       Expression predicate,
       List<String> allMeasurements,
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java
index 6acd4e1b716..2894ac2b432 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.queryengine.plan.planner;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.queryengine.exception.MemoryNotEnoughException;
 import org.apache.iotdb.db.queryengine.execution.driver.DataDriverContext;
 import org.apache.iotdb.db.queryengine.execution.fragment.DataNodeQueryContext;
@@ -80,7 +81,18 @@ public class LocalExecutionPlanner {
 
     // Generate pipelines, return the last pipeline data structure
     // TODO Replace operator with operatorFactory to build multiple driver for 
one pipeline
-    Operator root = plan.accept(new OperatorTreeGenerator(), context);
+    Operator root;
+    IClientSession.SqlDialect sqlDialect = 
instanceContext.getSessionInfo().getSqlDialect();
+    switch (sqlDialect) {
+      case TREE:
+        root = plan.accept(new OperatorTreeGenerator(), context);
+        break;
+      case TABLE:
+        root = plan.accept(new TableOperatorGenerator(), context);
+        break;
+      default:
+        throw new IllegalArgumentException(String.format("Unknown sql dialect: 
%s", sqlDialect));
+    }
 
     // check whether current free memory is enough to execute current query
     long estimatedMemorySize = checkMemory(root, 
instanceContext.getStateMachine());
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
index 273e949b37f..bd699c18b5e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
@@ -24,10 +24,13 @@ import 
org.apache.iotdb.db.queryengine.execution.driver.DataDriverContext;
 import org.apache.iotdb.db.queryengine.execution.operator.Operator;
 import org.apache.iotdb.db.queryengine.execution.operator.OperatorContext;
 import 
org.apache.iotdb.db.queryengine.execution.operator.process.FilterAndProjectOperator;
+import 
org.apache.iotdb.db.queryengine.execution.operator.process.LimitOperator;
+import 
org.apache.iotdb.db.queryengine.execution.operator.process.OffsetOperator;
 import 
org.apache.iotdb.db.queryengine.execution.operator.source.AlignedSeriesScanOperator;
 import 
org.apache.iotdb.db.queryengine.execution.operator.source.relational.TableScanOperator;
 import 
org.apache.iotdb.db.queryengine.execution.relational.ColumnTransformerBuilder;
 import org.apache.iotdb.db.queryengine.plan.analyze.PredicateUtils;
+import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
@@ -63,6 +66,8 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 import static java.util.Objects.requireNonNull;
 import static 
org.apache.iotdb.db.queryengine.execution.operator.source.relational.TableScanOperator.constructAlignedPath;
@@ -170,8 +175,8 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
 
     if (!predicateCanPushIntoScan) {
 
-      return constructFilterOperator(
-          pushDownPredicate,
+      return constructFilterAndProjectOperator(
+          Optional.of(pushDownPredicate),
           tableScanOperator,
           node.getOutputSymbols().stream()
               .map(Symbol::toSymbolReference)
@@ -221,11 +226,24 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
 
   @Override
   public Operator visitFilter(FilterNode node, LocalExecutionPlanContext 
context) {
-    return super.visitFilter(node, context);
+    TypeProvider typeProvider = context.getTypeProvider();
+    Optional<Expression> predicate = Optional.of(node.getPredicate());
+    Operator inputOperator = node.getChild().accept(this, context);
+    List<TSDataType> inputDataTypes = getInputColumnTypes(node, typeProvider);
+    Map<Symbol, List<InputLocation>> inputLocations = 
makeLayout(node.getChildren());
+
+    return constructFilterAndProjectOperator(
+        predicate,
+        inputOperator,
+        
node.getOutputSymbols().stream().map(Symbol::toSymbolReference).toArray(Expression[]::new),
+        inputDataTypes,
+        inputLocations,
+        node.getPlanNodeId(),
+        context);
   }
 
-  private Operator constructFilterOperator(
-      Expression predicate,
+  private Operator constructFilterAndProjectOperator(
+      Optional<Expression> predicate,
       Operator inputOperator,
       Expression[] projectExpressions,
       List<TSDataType> inputDataTypes,
@@ -238,36 +256,41 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
     // records LeafColumnTransformer of filter
     List<LeafColumnTransformer> filterLeafColumnTransformerList = new 
ArrayList<>();
 
-    // records common ColumnTransformer between filter and project expressions
-    List<ColumnTransformer> commonTransformerList = new ArrayList<>();
-
-    // records LeafColumnTransformer of project expressions
-    List<LeafColumnTransformer> projectLeafColumnTransformerList = new 
ArrayList<>();
-
     // records subexpression -> ColumnTransformer for filter
     Map<Expression, ColumnTransformer> filterExpressionColumnTransformerMap = 
new HashMap<>();
 
     ColumnTransformerBuilder visitor = new ColumnTransformerBuilder();
 
-    ColumnTransformerBuilder.Context filterColumnTransformerContext =
-        new ColumnTransformerBuilder.Context(
-            
context.getDriverContext().getFragmentInstanceContext().getSessionInfo(),
-            filterLeafColumnTransformerList,
-            inputLocations,
-            filterExpressionColumnTransformerMap,
-            ImmutableMap.of(),
-            ImmutableList.of(),
-            ImmutableList.of(),
-            0,
-            context.getTypeProvider());
-
     ColumnTransformer filterOutputTransformer =
-        visitor.process(predicate, filterColumnTransformerContext);
+        predicate
+            .map(
+                p -> {
+                  ColumnTransformerBuilder.Context 
filterColumnTransformerContext =
+                      new ColumnTransformerBuilder.Context(
+                          
context.getDriverContext().getFragmentInstanceContext().getSessionInfo(),
+                          filterLeafColumnTransformerList,
+                          inputLocations,
+                          filterExpressionColumnTransformerMap,
+                          ImmutableMap.of(),
+                          ImmutableList.of(),
+                          ImmutableList.of(),
+                          0,
+                          context.getTypeProvider());
+
+                  return visitor.process(p, filterColumnTransformerContext);
+                })
+            .orElse(null);
+
+    // records LeafColumnTransformer of project expressions
+    List<LeafColumnTransformer> projectLeafColumnTransformerList = new 
ArrayList<>();
 
     List<ColumnTransformer> projectOutputTransformerList = new ArrayList<>();
 
     Map<Expression, ColumnTransformer> projectExpressionColumnTransformerMap = 
new HashMap<>();
 
+    // records common ColumnTransformer between filter and project expressions
+    List<ColumnTransformer> commonTransformerList = new ArrayList<>();
+
     ColumnTransformerBuilder.Context projectColumnTransformerContext =
         new ColumnTransformerBuilder.Context(
             
context.getDriverContext().getFragmentInstanceContext().getSessionInfo(),
@@ -304,33 +327,73 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
         projectLeafColumnTransformerList,
         projectOutputTransformerList,
         false,
-        true);
+        predicate.isPresent());
   }
 
   @Override
   public Operator visitProject(ProjectNode node, LocalExecutionPlanContext 
context) {
+    TypeProvider typeProvider = context.getTypeProvider();
+    Optional<Expression> predicate;
+    Operator inputOperator;
+    List<TSDataType> inputDataTypes;
+    Map<Symbol, List<InputLocation>> inputLocations;
     if (node.getChild() instanceof FilterNode) {
       FilterNode filterNode = (FilterNode) node.getChild();
-      return constructFilterOperator(
-          filterNode.getPredicate(),
-          filterNode.getChild().accept(this, context),
-          node.getAssignments().getExpressions().toArray(new Expression[0]),
-          tableScanOperator.getResultDataTypes(),
-          makeLayout(Collections.singletonList(filterNode.getChild())),
-          node.getPlanNodeId(),
-          context);
+      predicate = Optional.of(filterNode.getPredicate());
+      inputOperator = filterNode.getChild().accept(this, context);
+      inputDataTypes = getInputColumnTypes(filterNode, typeProvider);
+      inputLocations = makeLayout(filterNode.getChildren());
+    } else {
+      predicate = Optional.empty();
+      inputOperator = node.getChild().accept(this, context);
+      inputDataTypes = getInputColumnTypes(node, typeProvider);
+      inputLocations = makeLayout(node.getChildren());
     }
-    return super.visitProject(node, context);
+
+    return constructFilterAndProjectOperator(
+        predicate,
+        inputOperator,
+        node.getAssignments().getExpressions().toArray(new Expression[0]),
+        inputDataTypes,
+        inputLocations,
+        node.getPlanNodeId(),
+        context);
+  }
+
+  private List<TSDataType> getInputColumnTypes(PlanNode node, TypeProvider 
typeProvider) {
+    return node.getChildren().stream()
+        .map(PlanNode::getOutputSymbols)
+        .flatMap(List::stream)
+        .map(s -> getTSDataType(typeProvider.get(s)))
+        .collect(Collectors.toList());
   }
 
   @Override
   public Operator visitLimit(LimitNode node, LocalExecutionPlanContext 
context) {
-    return super.visitLimit(node, context);
+    Operator child = node.getChild().accept(this, context);
+    OperatorContext operatorContext =
+        context
+            .getDriverContext()
+            .addOperatorContext(
+                context.getNextOperatorId(),
+                node.getPlanNodeId(),
+                LimitOperator.class.getSimpleName());
+
+    return new LimitOperator(operatorContext, node.getCount(), child);
   }
 
   @Override
   public Operator visitOffset(OffsetNode node, LocalExecutionPlanContext 
context) {
-    return super.visitOffset(node, context);
+    Operator child = node.getChild().accept(this, context);
+    OperatorContext operatorContext =
+        context
+            .getDriverContext()
+            .addOperatorContext(
+                context.getNextOperatorId(),
+                node.getPlanNodeId(),
+                OffsetOperator.class.getSimpleName());
+
+    return new OffsetOperator(operatorContext, node.getCount(), child);
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/TableModelTimePredicate.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/TableModelTimePredicate.java
new file mode 100644
index 00000000000..5a19fb08a71
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/TableModelTimePredicate.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.planner.plan;
+
+import org.apache.iotdb.db.queryengine.plan.analyze.PredicateUtils;
+import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Objects;
+
+public class TableModelTimePredicate implements TimePredicate {
+
+  private final Expression timePredicate;
+
+  public TableModelTimePredicate(Expression timePredicate) {
+    this.timePredicate = timePredicate;
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    throw new UnsupportedEncodingException();
+  }
+
+  @Override
+  public Filter convertPredicateToTimeFilter() {
+    return PredicateUtils.convertPredicateToTimeFilter(timePredicate);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    TableModelTimePredicate that = (TableModelTimePredicate) o;
+    return Objects.equals(timePredicate, that.timePredicate);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(timePredicate);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
index 17481074932..dbc82fcb5b9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java
@@ -46,4 +46,8 @@ public class LimitNode extends SingleChildProcessNode {
   public List<Symbol> getOutputSymbols() {
     return child.getOutputSymbols();
   }
+
+  public long getCount() {
+    return count;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
index 69ac2517e83..b1fa2db71ee 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java
@@ -38,4 +38,8 @@ public class OffsetNode extends SingleChildProcessNode {
   public List<Symbol> getOutputSymbols() {
     return child.getOutputSymbols();
   }
+
+  public long getCount() {
+    return count;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index 8bb2cecd3bc..583f1ec64ca 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 
 import org.apache.iotdb.commons.exception.IoTDBException;
+import org.apache.iotdb.db.protocol.session.IClientSession;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.QueryId;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
@@ -154,7 +155,9 @@ public class AnalyzerTest {
   private Analysis analyzeSQL(String sql, Metadata metadata) {
     try {
       Statement statement = sqlParser.createStatement(sql);
-      SessionInfo session = new SessionInfo(0, "test", ZoneId.systemDefault(), 
"testdb");
+      SessionInfo session =
+          new SessionInfo(
+              0, "test", ZoneId.systemDefault(), "testdb", 
IClientSession.SqlDialect.TABLE);
       StatementAnalyzerFactory statementAnalyzerFactory =
           new StatementAnalyzerFactory(metadata, sqlParser, nopAccessControl);
 

Reply via email to