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

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


The following commit(s) were added to refs/heads/ty/TableModelGrammar by this 
push:
     new bbb7846f4ce Add explain support, perfect the return type of diff 
function
bbb7846f4ce is described below

commit bbb7846f4cec3f024d321ef985329fd4f593845d
Author: Beyyes <[email protected]>
AuthorDate: Sat Jun 15 18:51:03 2024 +0800

    Add explain support, perfect the return type of diff function
---
 .../memory/StatementMemorySourceVisitor.java       |   4 +
 .../TableModelStatementMemorySourceContext.java    |  41 ++++++
 .../TableModelStatementMemorySourceVisitor.java    |  94 +++++++++++++
 .../plan/planner/plan/node/PlanGraphPrinter.java   |  54 +++++++
 .../plan/relational/analyzer/Analysis.java         |  20 ++-
 .../relational/analyzer/StatementAnalyzer.java     |   3 +-
 .../relational/cost/CachingTableStatsProvider.java |  51 -------
 .../plan/relational/cost/ColumnStatistics.java     | 156 ---------------------
 .../plan/relational/cost/DoubleRange.java          | 104 --------------
 .../queryengine/plan/relational/cost/Estimate.java |  84 -----------
 .../plan/relational/cost/StatsUtil.java            |  43 ------
 .../plan/relational/cost/TableStatistics.java      | 112 ---------------
 .../plan/relational/cost/TableStatsProvider.java   |  20 ---
 .../relational/metadata/TableMetadataImpl.java     |   2 +-
 .../plan/relational/planner/LogicalPlanner.java    |  16 ++-
 .../relational/planner/RelationalModelPlanner.java |  19 +--
 .../planner/optimizations/IndexScan.java           |  67 ++++-----
 17 files changed, 259 insertions(+), 631 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/StatementMemorySourceVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/StatementMemorySourceVisitor.java
index 7a37902dbb9..20bce13a41b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/StatementMemorySourceVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/StatementMemorySourceVisitor.java
@@ -100,6 +100,10 @@ public class StatementMemorySourceVisitor
             new PlanGraphPrinter.GraphContext(
                 
context.getQueryContext().getTypeProvider().getTemplatedInfo()));
 
+    return getStatementMemorySource(header, lines);
+  }
+
+  static StatementMemorySource getStatementMemorySource(DatasetHeader header, 
List<String> lines) {
     TsBlockBuilder builder = new 
TsBlockBuilder(Collections.singletonList(TSDataType.TEXT));
     lines.forEach(
         line -> {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceContext.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceContext.java
new file mode 100644
index 00000000000..a4b849fb385
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceContext.java
@@ -0,0 +1,41 @@
+/*
+ * 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.execution.memory;
+
+import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
+
+public class TableModelStatementMemorySourceContext {
+  private final MPPQueryContext queryContext;
+  private final Analysis analysis;
+
+  public TableModelStatementMemorySourceContext(MPPQueryContext queryContext, 
Analysis analysis) {
+    this.queryContext = queryContext;
+    this.analysis = analysis;
+  }
+
+  public MPPQueryContext getQueryContext() {
+    return queryContext;
+  }
+
+  public Analysis getAnalysis() {
+    return analysis;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
new file mode 100644
index 00000000000..fbe6fe2723e
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.execution.memory;
+
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
+import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
+import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
+import org.apache.iotdb.db.queryengine.plan.planner.LocalExecutionPlanner;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanGraphPrinter;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute.ExchangeNodeGenerator;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Explain;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Node;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.block.TsBlock;
+
+import java.util.Collections;
+import java.util.List;
+
+import static 
org.apache.iotdb.db.queryengine.common.header.DatasetHeader.EMPTY_HEADER;
+import static 
org.apache.iotdb.db.queryengine.plan.execution.memory.StatementMemorySourceVisitor.getStatementMemorySource;
+
+public class TableModelStatementMemorySourceVisitor
+    extends AstVisitor<StatementMemorySource, 
TableModelStatementMemorySourceContext> {
+
+  @Override
+  public StatementMemorySource visitNode(
+      Node node, TableModelStatementMemorySourceContext context) {
+    DatasetHeader datasetHeader = context.getAnalysis().getRespDatasetHeader();
+    return new StatementMemorySource(
+        new TsBlock(0), datasetHeader == null ? EMPTY_HEADER : datasetHeader);
+  }
+
+  @Override
+  public StatementMemorySource visitExplain(
+      Explain node, TableModelStatementMemorySourceContext context) {
+    context.getAnalysis().setStatement(node.getStatement());
+    DatasetHeader header =
+        new DatasetHeader(
+            Collections.singletonList(
+                new ColumnHeader(IoTDBConstant.COLUMN_DISTRIBUTION_PLAN, 
TSDataType.TEXT)),
+            true);
+    LogicalQueryPlan logicalPlan =
+        new 
org.apache.iotdb.db.queryengine.plan.relational.planner.LogicalPlanner(
+                context.getQueryContext(),
+                LocalExecutionPlanner.getInstance().metadata,
+                context.getQueryContext().getSession(),
+                ClusterPartitionFetcher.getInstance(),
+                WarningCollector.NOOP)
+            .plan(context.getAnalysis());
+    if (context.getAnalysis().getDataPartition() == null
+        || context.getAnalysis().getDataPartition().isEmpty()) {
+      return new StatementMemorySource(new TsBlock(0), header);
+    }
+
+    // TODO(beyyes) adapt this logic after optimize ExchangeNodeAdder
+    ExchangeNodeGenerator.PlanContext exchangeContext =
+        new ExchangeNodeGenerator.PlanContext(context.getQueryContext());
+    List<PlanNode> distributedPlanNodeResult =
+        new ExchangeNodeGenerator().visitPlan(logicalPlan.getRootNode(), 
exchangeContext);
+
+    List<String> lines =
+        distributedPlanNodeResult
+            .get(0)
+            .accept(
+                new PlanGraphPrinter(),
+                new PlanGraphPrinter.GraphContext(
+                    
context.getQueryContext().getTypeProvider().getTemplatedInfo()));
+
+    return getStatementMemorySource(header, lines);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
index 308e2afd22f..380a7f60cbc 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
@@ -66,6 +66,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.AggregationDe
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.CrossSeriesAggregationDescriptor;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.IntoPathDescriptor;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 
 import org.apache.commons.lang3.Validate;
 import org.apache.tsfile.utils.Pair;
@@ -598,6 +599,59 @@ public class PlanGraphPrinter extends 
PlanVisitor<List<String>, PlanGraphPrinter
     return render(node, boxValue, context);
   }
 
+  // =============== Methods below are used for table model ================
+  @Override
+  public List<String> visitTableScan(TableScanNode node, GraphContext context) 
{
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("TableScan-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("QualifiedTableName: %s", 
node.getQualifiedTableName()));
+    boxValue.add(String.format("OutputSymbols: %s", node.getOutputSymbols()));
+    boxValue.add(String.format("DeviceEntriesSize: %s", 
node.getDeviceEntries().size()));
+    boxValue.add(String.format("ScanOrder: %s", node.getScanOrder()));
+    if (node.getPushDownPredicate() != null) {
+      boxValue.add(String.format("PushDownPredicate: %s", 
node.getPushDownPredicate()));
+    }
+    if (node.getPushDownOffset() > 0) {
+      boxValue.add(String.format("PushDownOffset: %s", 
node.getPushDownOffset()));
+    }
+    if (node.getPushDownLimit() > 0) {
+      boxValue.add(String.format("PushDownLimit: %s", 
node.getPushDownLimit()));
+    }
+    boxValue.add(String.format("RegionId: %s", 
node.getRegionReplicaSet().getRegionId().getId()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitFilter(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Filter-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("Predicate: %s", node.getPredicate()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitProject(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Project-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("OutputSymbols: %s", node.getOutputSymbols()));
+    boxValue.add(String.format("Expressions: %s", 
node.getAssignments().getMap().values()));
+    return render(node, boxValue, context);
+  }
+
+  @Override
+  public List<String> visitOutput(
+      org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode 
node,
+      GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("Output-%s", node.getPlanNodeId().getId()));
+    boxValue.add(String.format("OutputSymbols: %s", node.getOutputSymbols()));
+    return render(node, boxValue, context);
+  }
+
   private String printRegion(TRegionReplicaSet regionReplicaSet) {
     return String.format(
         "Partition: %s",
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
index c4708ad1960..4d019248d86 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java
@@ -27,6 +27,8 @@ import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
 import org.apache.iotdb.db.queryengine.plan.analyze.IAnalysis;
 import 
org.apache.iotdb.db.queryengine.plan.execution.memory.StatementMemorySource;
+import 
org.apache.iotdb.db.queryengine.plan.execution.memory.TableModelStatementMemorySourceContext;
+import 
org.apache.iotdb.db.queryengine.plan.execution.memory.TableModelStatementMemorySourceVisitor;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.TimePredicate;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
@@ -86,11 +88,10 @@ import static java.util.Collections.unmodifiableList;
 import static java.util.Collections.unmodifiableMap;
 import static java.util.Collections.unmodifiableSet;
 import static java.util.Objects.requireNonNull;
-import static 
org.apache.iotdb.db.queryengine.common.header.DatasetHeader.EMPTY_HEADER;
 
 public class Analysis implements IAnalysis {
 
-  @Nullable private final Statement root;
+  @Nullable private Statement root;
 
   private final Map<NodeRef<Parameter>, Expression> parameters;
 
@@ -269,6 +270,10 @@ public class Analysis implements IAnalysis {
     return getScope(root);
   }
 
+  public void setStatement(Statement statement) {
+    this.root = statement;
+  }
+
   public void setScope(Node node, Scope scope) {
     scopes.put(NodeRef.of(node), scope);
   }
@@ -614,11 +619,12 @@ public class Analysis implements IAnalysis {
 
   @Override
   public TsBlock constructResultForMemorySource(MPPQueryContext context) {
-    StatementMemorySource source =
-        new StatementMemorySource(
-            new TsBlock(0), respDatasetHeader == null ? EMPTY_HEADER : 
respDatasetHeader);
-    setRespDatasetHeader(source.getDatasetHeader());
-    return source.getTsBlock();
+    requireNonNull(getStatement(), "root statement is analysis is null");
+    StatementMemorySource memorySource =
+        new TableModelStatementMemorySourceVisitor()
+            .process(getStatement(), new 
TableModelStatementMemorySourceContext(context, this));
+    setRespDatasetHeader(memorySource.getDatasetHeader());
+    return memorySource.getTsBlock();
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
index a15ed482daa..1fcc4e89024 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
@@ -359,7 +359,8 @@ public class StatementAnalyzer {
 
     @Override
     protected Scope visitExplain(Explain node, Optional<Scope> context) {
-      throw new SemanticException("Explain statement is not supported yet.");
+      analysis.setFinishQueryAfterAnalyze();
+      return visitQuery((Query) node.getStatement(), context);
     }
 
     @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/CachingTableStatsProvider.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/CachingTableStatsProvider.java
deleted file mode 100644
index d3c9da443ab..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/CachingTableStatsProvider.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
-import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle;
-import org.apache.iotdb.session.Session;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import static java.util.Objects.requireNonNull;
-
-public class CachingTableStatsProvider implements TableStatsProvider {
-  private final Metadata metadata;
-  private final Session session;
-
-  private final Map<TableHandle, TableStatistics> cache = new WeakHashMap<>();
-
-  public CachingTableStatsProvider(Metadata metadata, Session session) {
-    this.metadata = requireNonNull(metadata, "metadata is null");
-    this.session = requireNonNull(session, "session is null");
-  }
-
-  @Override
-  public TableStatistics getTableStatistics(TableHandle tableHandle) {
-    TableStatistics stats = cache.get(tableHandle);
-    if (stats == null) {
-      // stats = metadata.getTableStatistics(session, tableHandle);
-      cache.put(tableHandle, TableStatistics.empty());
-    }
-    return stats;
-  }
-
-  public Map<TableHandle, TableStatistics> getCachedTableStatistics() {
-    return ImmutableMap.copyOf(cache);
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/ColumnStatistics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/ColumnStatistics.java
deleted file mode 100644
index 4895d9096e6..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/ColumnStatistics.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-
-public final class ColumnStatistics {
-  private static final ColumnStatistics EMPTY =
-      new ColumnStatistics(
-          Estimate.unknown(), Estimate.unknown(), Estimate.unknown(), 
Optional.empty());
-
-  private final Estimate nullsFraction;
-  private final Estimate distinctValuesCount;
-  private final Estimate dataSize;
-  private final Optional<DoubleRange> range;
-
-  public static ColumnStatistics empty() {
-    return EMPTY;
-  }
-
-  public ColumnStatistics(
-      Estimate nullsFraction,
-      Estimate distinctValuesCount,
-      Estimate dataSize,
-      Optional<DoubleRange> range) {
-    this.nullsFraction = requireNonNull(nullsFraction, "nullsFraction is 
null");
-    if (!nullsFraction.isUnknown()) {
-      if (nullsFraction.getValue() < 0 || nullsFraction.getValue() > 1) {
-        throw new IllegalArgumentException(
-            format("nullsFraction must be between 0 and 1: %s", 
nullsFraction.getValue()));
-      }
-    }
-    this.distinctValuesCount = requireNonNull(distinctValuesCount, 
"distinctValuesCount is null");
-    if (!distinctValuesCount.isUnknown() && distinctValuesCount.getValue() < 
0) {
-      throw new IllegalArgumentException(
-          format(
-              "distinctValuesCount must be greater than or equal to 0: %s",
-              distinctValuesCount.getValue()));
-    }
-    this.dataSize = requireNonNull(dataSize, "dataSize is null");
-    if (!dataSize.isUnknown() && dataSize.getValue() < 0) {
-      throw new IllegalArgumentException(
-          format("dataSize must be greater than or equal to 0: %s", 
dataSize.getValue()));
-    }
-    this.range = requireNonNull(range, "range is null");
-  }
-
-  public Estimate getNullsFraction() {
-    return nullsFraction;
-  }
-
-  public Estimate getDistinctValuesCount() {
-    return distinctValuesCount;
-  }
-
-  public Estimate getDataSize() {
-    return dataSize;
-  }
-
-  public Optional<DoubleRange> getRange() {
-    return range;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    ColumnStatistics that = (ColumnStatistics) o;
-    return Objects.equals(nullsFraction, that.nullsFraction)
-        && Objects.equals(distinctValuesCount, that.distinctValuesCount)
-        && Objects.equals(dataSize, that.dataSize)
-        && Objects.equals(range, that.range);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(nullsFraction, distinctValuesCount, dataSize, range);
-  }
-
-  @Override
-  public String toString() {
-    return "ColumnStatistics{"
-        + "nullsFraction="
-        + nullsFraction
-        + ", distinctValuesCount="
-        + distinctValuesCount
-        + ", dataSize="
-        + dataSize
-        + ", range="
-        + range
-        + '}';
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  /**
-   * If one of the estimates below is unspecified (i.e. left as "unknown"), 
the optimizer may not be
-   * able to derive the statistics needed for performing cost-based query plan 
optimizations.
-   */
-  public static final class Builder {
-    private Estimate nullsFraction = Estimate.unknown();
-    private Estimate distinctValuesCount = Estimate.unknown();
-    private Estimate dataSize = Estimate.unknown();
-    private Optional<DoubleRange> range = Optional.empty();
-
-    public Builder setNullsFraction(Estimate nullsFraction) {
-      this.nullsFraction = requireNonNull(nullsFraction, "nullsFraction is 
null");
-      return this;
-    }
-
-    public Builder setDistinctValuesCount(Estimate distinctValuesCount) {
-      this.distinctValuesCount = requireNonNull(distinctValuesCount, 
"distinctValuesCount is null");
-      return this;
-    }
-
-    public Builder setDataSize(Estimate dataSize) {
-      this.dataSize = requireNonNull(dataSize, "dataSize is null");
-      return this;
-    }
-
-    public Builder setRange(DoubleRange range) {
-      this.range = Optional.of(requireNonNull(range, "range is null"));
-      return this;
-    }
-
-    public Builder setRange(Optional<DoubleRange> range) {
-      this.range = requireNonNull(range, "range is null");
-      return this;
-    }
-
-    public ColumnStatistics build() {
-      return new ColumnStatistics(nullsFraction, distinctValuesCount, 
dataSize, range);
-    }
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/DoubleRange.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/DoubleRange.java
deleted file mode 100644
index 2baad720db5..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/DoubleRange.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import org.apache.tsfile.read.common.type.Type;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.OptionalDouble;
-
-import static java.lang.Double.isNaN;
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-import static 
org.apache.iotdb.db.queryengine.plan.relational.cost.StatsUtil.toStatsRepresentation;
-
-public class DoubleRange {
-  private final double min;
-  private final double max;
-
-  /** Creates DoubleRange from Trino native representation. */
-  public static Optional<DoubleRange> from(
-      Type type, Object minTrinoNativeValue, Object maxTrinoNativeValue) {
-    requireNonNull(minTrinoNativeValue, "minTrinoNativeValue is null");
-    requireNonNull(maxTrinoNativeValue, "maxTrinoNativeValue is null");
-
-    OptionalDouble min = toStatsRepresentation(type, minTrinoNativeValue);
-    OptionalDouble max = toStatsRepresentation(type, maxTrinoNativeValue);
-
-    if (!min.isPresent() && !max.isPresent()) {
-      return Optional.empty();
-    }
-    if (!min.isPresent() || !max.isPresent()) {
-      throw new IllegalStateException(
-          format(
-              "One of min/max was converted to stats representation while the 
other was not for type %s: %s, %s",
-              type, min, max));
-    }
-    return Optional.of(new DoubleRange(min.getAsDouble(), max.getAsDouble()));
-  }
-
-  public DoubleRange(double min, double max) {
-    if (isNaN(min)) {
-      throw new IllegalArgumentException("min must not be NaN");
-    }
-    if (isNaN(max)) {
-      throw new IllegalArgumentException("max must not be NaN");
-    }
-    if (min > max) {
-      throw new IllegalArgumentException(
-          format("max must be greater than or equal to min. min: %s. max: %s. 
", min, max));
-    }
-    this.min = min;
-    this.max = max;
-  }
-
-  public double getMin() {
-    return min;
-  }
-
-  public double getMax() {
-    return max;
-  }
-
-  public static DoubleRange union(DoubleRange first, DoubleRange second) {
-    requireNonNull(first, "first is null");
-    requireNonNull(second, "second is null");
-    return new DoubleRange(min(first.min, second.min), max(first.max, 
second.max));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    DoubleRange range = (DoubleRange) o;
-    return Double.compare(range.min, min) == 0 && Double.compare(range.max, 
max) == 0;
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(min, max);
-  }
-
-  @Override
-  public String toString() {
-    return "DoubleRange{" + "min=" + min + ", max=" + max + '}';
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/Estimate.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/Estimate.java
deleted file mode 100644
index 85366b89090..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/Estimate.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import java.util.Objects;
-
-import static java.lang.Double.NaN;
-import static java.lang.Double.isInfinite;
-import static java.lang.Double.isNaN;
-
-public final class Estimate {
-  // todo eventually add some notion of statistic reliability
-  //      Skipping for now as there hard to compute it properly and so far we 
do not have
-  //      usecase for that.
-
-  private static final Estimate UNKNOWN = new Estimate(NaN);
-  private static final Estimate ZERO = new Estimate(0);
-
-  private final double value;
-
-  public static Estimate unknown() {
-    return UNKNOWN;
-  }
-
-  public static Estimate zero() {
-    return ZERO;
-  }
-
-  public static Estimate of(double value) {
-    if (isNaN(value)) {
-      throw new IllegalArgumentException("value is NaN");
-    }
-    if (isInfinite(value)) {
-      throw new IllegalArgumentException("value is infinite");
-    }
-    return new Estimate(value);
-  }
-
-  private Estimate(double value) {
-    this.value = value;
-  }
-
-  public boolean isUnknown() {
-    return isNaN(value);
-  }
-
-  public double getValue() {
-    return value;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    Estimate estimate = (Estimate) o;
-    return Double.compare(estimate.value, value) == 0;
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(value);
-  }
-
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/StatsUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/StatsUtil.java
deleted file mode 100644
index 7f9180782fc..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/StatsUtil.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import org.apache.tsfile.read.common.type.Type;
-
-import java.util.OptionalDouble;
-
-import static java.util.Objects.requireNonNull;
-import static org.apache.tsfile.read.common.type.BooleanType.BOOLEAN;
-import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE;
-import static org.apache.tsfile.read.common.type.IntType.INT32;
-
-public final class StatsUtil {
-  private StatsUtil() {}
-
-  public static OptionalDouble toStatsRepresentation(Type type, Object value) {
-    requireNonNull(type, "type is null");
-    requireNonNull(value, "value is null");
-
-    if (type == BOOLEAN) {
-      return OptionalDouble.of((boolean) value ? 1 : 0);
-    }
-    if (type == INT32) {
-      return OptionalDouble.of((long) value);
-    }
-    if (type == DOUBLE) {
-      return OptionalDouble.of((double) value);
-    }
-    return OptionalDouble.empty();
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatistics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatistics.java
deleted file mode 100644
index 9a610107d91..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatistics.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnHandle;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
-import static java.lang.String.format;
-import static java.util.Collections.unmodifiableMap;
-import static java.util.Objects.requireNonNull;
-
-public final class TableStatistics {
-  private static final TableStatistics EMPTY = 
TableStatistics.builder().build();
-
-  private final Estimate rowCount;
-  private final Map<ColumnHandle, ColumnStatistics> columnStatistics;
-
-  public static TableStatistics empty() {
-    return EMPTY;
-  }
-
-  public TableStatistics(Estimate rowCount, Map<ColumnHandle, 
ColumnStatistics> columnStatistics) {
-    this.rowCount = requireNonNull(rowCount, "rowCount cannot be null");
-    if (!rowCount.isUnknown() && rowCount.getValue() < 0) {
-      throw new IllegalArgumentException(
-          format("rowCount must be greater than or equal to 0: %s", 
rowCount.getValue()));
-    }
-    this.columnStatistics =
-        unmodifiableMap(requireNonNull(columnStatistics, "columnStatistics 
cannot be null"));
-  }
-
-  public Estimate getRowCount() {
-    return rowCount;
-  }
-
-  public Map<ColumnHandle, ColumnStatistics> getColumnStatistics() {
-    return columnStatistics;
-  }
-
-  public boolean isEmpty() {
-    return equals(empty());
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    TableStatistics that = (TableStatistics) o;
-    return Objects.equals(rowCount, that.rowCount)
-        && Objects.equals(columnStatistics, that.columnStatistics);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(rowCount, columnStatistics);
-  }
-
-  @Override
-  public String toString() {
-    return "TableStatistics{"
-        + "rowCount="
-        + rowCount
-        + ", columnStatistics="
-        + columnStatistics
-        + '}';
-  }
-
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public static final class Builder {
-    private final Map<ColumnHandle, ColumnStatistics> columnStatisticsMap = 
new LinkedHashMap<>();
-    private Estimate rowCount = Estimate.unknown();
-
-    public Builder setRowCount(Estimate rowCount) {
-      this.rowCount = requireNonNull(rowCount, "rowCount cannot be null");
-      return this;
-    }
-
-    public Builder setColumnStatistics(
-        ColumnHandle columnHandle, ColumnStatistics columnStatistics) {
-      requireNonNull(columnHandle, "columnHandle cannot be null");
-      requireNonNull(columnStatistics, "columnStatistics cannot be null");
-      this.columnStatisticsMap.put(columnHandle, columnStatistics);
-      return this;
-    }
-
-    public TableStatistics build() {
-      return new TableStatistics(rowCount, columnStatisticsMap);
-    }
-  }
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatsProvider.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatsProvider.java
deleted file mode 100644
index 72fd4d6932e..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/cost/TableStatsProvider.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.iotdb.db.queryengine.plan.relational.cost;
-
-import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle;
-
-public interface TableStatsProvider {
-  TableStatistics getTableStatistics(TableHandle tableHandle);
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
index 67f030ede35..f3ff0b59834 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
@@ -123,7 +123,7 @@ public class TableMetadataImpl implements Metadata {
                 + functionName.toLowerCase(Locale.ENGLISH)
                 + " only supports one numeric data types [INT32, INT64, FLOAT, 
DOUBLE] and one boolean");
       }
-      return argumentTypes.get(0);
+      return DOUBLE;
     } else if 
(BuiltinScalarFunction.ROUND.getFunctionName().equalsIgnoreCase(functionName)) {
       if (!isOneNumericType(argumentTypes) && 
!isTwoNumericType(argumentTypes)) {
         throw new SemanticException(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
index 719ede30231..a7537c4e680 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java
@@ -14,7 +14,6 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.planner;
 
-import org.apache.iotdb.commons.exception.IoTDBException;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
@@ -34,6 +33,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.Pru
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RelationalPlanOptimizer;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RemoveRedundantIdentityProjections;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.SimplifyExpressions;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Explain;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Query;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Table;
@@ -84,7 +84,7 @@ public class LogicalPlanner {
             new IndexScan());
   }
 
-  public LogicalQueryPlan plan(Analysis analysis) throws IoTDBException {
+  public LogicalQueryPlan plan(Analysis analysis) {
     PlanNode planNode = planStatement(analysis, analysis.getStatement());
 
     relationalPlanOptimizers.forEach(
@@ -95,17 +95,19 @@ public class LogicalPlanner {
     return new LogicalQueryPlan(context, planNode);
   }
 
-  private PlanNode planStatement(Analysis analysis, Statement statement) 
throws IoTDBException {
+  private PlanNode planStatement(Analysis analysis, Statement statement) {
     return createOutputPlan(planStatementWithoutOutput(analysis, statement), 
analysis);
   }
 
-  private RelationPlan planStatementWithoutOutput(Analysis analysis, Statement 
statement)
-      throws IoTDBException {
+  private RelationPlan planStatementWithoutOutput(Analysis analysis, Statement 
statement) {
     if (statement instanceof Query) {
       return createRelationPlan(analysis, (Query) statement);
     }
-    throw new IoTDBException(
-        "Unsupported statement type " + statement.getClass().getSimpleName(), 
-1);
+    if (statement instanceof Explain) {
+      return createRelationPlan(analysis, (Query) ((Explain) 
statement).getStatement());
+    }
+    throw new IllegalStateException(
+        "Unsupported statement type: " + statement.getClass().getSimpleName());
   }
 
   private PlanNode createOutputPlan(RelationPlan plan, Analysis analysis) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
index b936555d401..60189c42f63 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationalModelPlanner.java
@@ -24,7 +24,6 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.client.IClientManager;
 import 
org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient;
 import org.apache.iotdb.commons.client.sync.SyncDataNodeInternalServiceClient;
-import org.apache.iotdb.commons.exception.IoTDBException;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.execution.QueryStateMachine;
 import org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector;
@@ -108,17 +107,13 @@ public class RelationalModelPlanner implements IPlanner {
 
   @Override
   public LogicalQueryPlan doLogicalPlan(IAnalysis analysis, MPPQueryContext 
context) {
-    try {
-      return new LogicalPlanner(
-              context,
-              metadata,
-              context.getSession(),
-              ClusterPartitionFetcher.getInstance(),
-              warningCollector)
-          .plan((Analysis) analysis);
-    } catch (IoTDBException e) {
-      throw new RuntimeException(e);
-    }
+    return new LogicalPlanner(
+            context,
+            metadata,
+            context.getSession(),
+            ClusterPartitionFetcher.getInstance(),
+            warningCollector)
+        .plan((Analysis) analysis);
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
index 4c2c24e6678..1aa4c5413d6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
@@ -35,7 +35,6 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 
-import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.read.filter.basic.Filter;
 import org.apache.tsfile.utils.Pair;
 
@@ -116,40 +115,41 @@ public class IndexScan implements RelationalPlanOptimizer 
{
                   metadataExpressions,
                   attributeColumns);
       node.setDeviceEntries(deviceEntries);
-
-      String treeModelDatabase = "root." + dbName;
-      Set<IDeviceID> deviceIDSet =
-          
deviceEntries.stream().map(DeviceEntry::getDeviceID).collect(Collectors.toSet());
-
-      DataPartition dataPartition =
-          fetchDataPartitionByDevices(
-              deviceIDSet,
-              treeModelDatabase,
-              context.getQueryContext().getGlobalTimeFilter(),
-              context.getPartitionFetcher());
-      context.getAnalysis().setDataPartition(dataPartition);
-
-      if (dataPartition.getDataPartitionMap().size() > 1) {
-        throw new IllegalStateException(
-            "Table model can only process data only in one database yet!");
-      }
-
-      if (dataPartition.getDataPartitionMap().isEmpty()) {
+      if (deviceEntries.isEmpty()) {
         context.getAnalysis().setFinishQueryAfterAnalyze();
       } else {
-        Set<TRegionReplicaSet> regionReplicaSet = new HashSet<>();
-        for (Map.Entry<
-                String, Map<TSeriesPartitionSlot, Map<TTimePartitionSlot, 
List<TRegionReplicaSet>>>>
-            e1 : dataPartition.getDataPartitionMap().entrySet()) {
-          for (Map.Entry<TSeriesPartitionSlot, Map<TTimePartitionSlot, 
List<TRegionReplicaSet>>>
-              e2 : e1.getValue().entrySet()) {
-            for (Map.Entry<TTimePartitionSlot, List<TRegionReplicaSet>> e3 :
-                e2.getValue().entrySet()) {
-              regionReplicaSet.addAll(e3.getValue());
+        String treeModelDatabase = "root." + dbName;
+        DataPartition dataPartition =
+            fetchDataPartitionByDevices(
+                deviceEntries,
+                treeModelDatabase,
+                context.getQueryContext().getGlobalTimeFilter(),
+                context.getPartitionFetcher());
+        context.getAnalysis().setDataPartition(dataPartition);
+
+        if (dataPartition.getDataPartitionMap().size() > 1) {
+          throw new IllegalStateException(
+              "Table model can only process data only in one database yet!");
+        }
+
+        if (dataPartition.getDataPartitionMap().isEmpty()) {
+          context.getAnalysis().setFinishQueryAfterAnalyze();
+        } else {
+          Set<TRegionReplicaSet> regionReplicaSet = new HashSet<>();
+          for (Map.Entry<
+                  String,
+                  Map<TSeriesPartitionSlot, Map<TTimePartitionSlot, 
List<TRegionReplicaSet>>>>
+              e1 : dataPartition.getDataPartitionMap().entrySet()) {
+            for (Map.Entry<TSeriesPartitionSlot, Map<TTimePartitionSlot, 
List<TRegionReplicaSet>>>
+                e2 : e1.getValue().entrySet()) {
+              for (Map.Entry<TTimePartitionSlot, List<TRegionReplicaSet>> e3 :
+                  e2.getValue().entrySet()) {
+                regionReplicaSet.addAll(e3.getValue());
+              }
             }
           }
+          node.setRegionReplicaSetList(new ArrayList<>(regionReplicaSet));
         }
-        node.setRegionReplicaSetList(new ArrayList<>(regionReplicaSet));
       }
 
       return node;
@@ -157,7 +157,7 @@ public class IndexScan implements RelationalPlanOptimizer {
   }
 
   private static DataPartition fetchDataPartitionByDevices(
-      Set<IDeviceID> deviceSet,
+      List<DeviceEntry> deviceEntries,
       String database,
       Filter globalTimeFilter,
       IPartitionFetcher partitionFetcher) {
@@ -173,9 +173,10 @@ public class IndexScan implements RelationalPlanOptimizer {
     }
 
     Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new 
HashMap<>();
-    for (IDeviceID deviceID : deviceSet) {
+    for (DeviceEntry deviceEntry : deviceEntries) {
       DataPartitionQueryParam queryParam =
-          new DataPartitionQueryParam(deviceID, res.left, res.right.left, 
res.right.right);
+          new DataPartitionQueryParam(
+              deviceEntry.getDeviceID(), res.left, res.right.left, 
res.right.right);
       sgNameToQueryParamsMap.computeIfAbsent(database, key -> new 
ArrayList<>()).add(queryParam);
     }
 

Reply via email to