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

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


The following commit(s) were added to refs/heads/master by this push:
     new 85524b0e832 Support where condition in show / count devices
85524b0e832 is described below

commit 85524b0e832399bb141b755e6a0e9e5cd9007863
Author: Caideyipi <[email protected]>
AuthorDate: Fri Aug 16 10:33:04 2024 +0800

    Support where condition in show / count devices
---
 .../relational/it/schema/IoTDBDeviceQueryIT.java   |  65 ++++++++++++-
 .../operator/schema/SchemaCountOperator.java       |   4 +-
 .../schema/source/DevicePredicateFilter.java       |  51 ++++++++++
 .../schema/source/SchemaSourceFactory.java         |  21 ++---
 .../schema/source/TableDeviceQuerySource.java      |  77 ++++++++-------
 .../TableModelStatementMemorySourceVisitor.java    |  32 +++++--
 .../plan/planner/TableOperatorGenerator.java       |  50 +++++++---
 .../node/metadata/read/TableDeviceFetchNode.java   |   6 --
 .../metadata/read/TableDeviceQueryCountNode.java   |   8 ++
 .../relational/analyzer/StatementAnalyzer.java     |  92 +++++++++++++++++-
 .../schema/CheckSchemaPredicateVisitor.java        |  24 +++--
 .../schema/ExtractPredicateColumnNameVisitor.java  |  11 ++-
 .../plan/relational/metadata/MetadataUtil.java     |   8 +-
 .../metadata/fetcher/SchemaPredicateUtil.java      |   5 +-
 .../metadata/fetcher/TableDeviceSchemaFetcher.java | 103 +++++++++++++--------
 .../plan/relational/planner/LogicalPlanner.java    |  66 +++----------
 .../distribute/TableModelQueryFragmentPlanner.java |   5 +-
 .../TableModelTypeProviderExtractor.java           |  24 +++++
 .../sql/ast/AbstractQueryDeviceWithCache.java      | 103 +++++++++++++++++++++
 ...ueryDevice.java => AbstractTraverseDevice.java} |  75 +++++++++++----
 .../plan/relational/sql/ast/CountDevice.java       |  30 +++++-
 .../plan/relational/sql/ast/ShowDevice.java        |  41 +++++---
 .../plan/relational/sql/parser/AstBuilder.java     |  14 ++-
 .../schemaengine/schemaregion/ISchemaRegion.java   |   5 +-
 .../schemaregion/impl/SchemaRegionMemoryImpl.java  |   9 +-
 .../schemaregion/impl/SchemaRegionPBTreeImpl.java  |   5 +-
 .../mtree/impl/mem/MTreeBelowSGMemoryImpl.java     |  31 +------
 .../read/resp/info/impl/ShowDevicesResult.java     |  18 ++++
 .../schemaRegion/SchemaRegionTableDeviceTest.java  |  74 ++-------------
 .../schemaRegion/SchemaRegionTestUtil.java         |   6 +-
 .../apache/iotdb/commons/schema/table/TsTable.java |   6 +-
 31 files changed, 734 insertions(+), 335 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceQueryIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceQueryIT.java
index 168fbaa715a..ee25eeccd75 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceQueryIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceQueryIT.java
@@ -37,6 +37,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Collections;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 @RunWith(IoTDBTestRunner.class)
@@ -66,6 +67,7 @@ public class IoTDBDeviceQueryIT {
       statement.execute(
           "insert into table0(region_id, plant_id, device_id, model, 
temperature, humidity) values('1', '5', '3', 'A', 37.6, 111.1)");
 
+      // Test plain show / count
       TestUtils.assertResultSetEqual(
           statement.executeQuery("show devices from table0"),
           "region_id,plant_id,device_id,model,",
@@ -83,18 +85,77 @@ public class IoTDBDeviceQueryIT {
           "count(devices),",
           Collections.singleton("0,"));
 
+      // Test show / count with where expression
+      // Test AND
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("show devices from table0 where region_id = 
'1' and model = 'A'"),
+          "region_id,plant_id,device_id,model,",
+          Collections.singleton("1,5,3,A,"));
+      // Test OR
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery(
+              "count devices from table0 where region_id = '1' or plant_id 
like '%'"),
+          "count(devices),",
+          Collections.singleton("1,"));
+      // Test complicated query
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("show devices from table0 where region_id < 
plant_id"),
+          "region_id,plant_id,device_id,model,",
+          Collections.singleton("1,5,3,A,"));
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("count devices from table0 where region_id < 
plant_id"),
+          "count(devices),",
+          Collections.singleton("1,"));
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery(
+              "count devices from table0 where substring(region_id, 
cast(plant_id as int32), 1) < plant_id"),
+          "count(devices),",
+          Collections.singleton("1,"));
+      // Test get from cache
+      statement.executeQuery(
+          "select * from table0 where region_id = '1' and plant_id in ('3', 
'5') and device_id = '3'");
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery(
+              "show devices from table0 where region_id = '1' and plant_id in 
('3', '5') and device_id = '3'"),
+          "region_id,plant_id,device_id,model,",
+          Collections.singleton("1,5,3,A,"));
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery(
+              "count devices from table0 where region_id = '1' and plant_id in 
('3', '5') and device_id = '3'"),
+          "count(devices),",
+          Collections.singleton("1,"));
+      // Test filter
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("count devices from table0 where region_id >= 
'2'"),
+          "count(devices),",
+          Collections.singleton("0,"));
+
       try {
         statement.executeQuery("show devices from table2");
         fail("Show devices shall fail for non-exist table");
       } catch (final Exception e) {
-        // Pass
+        assertEquals("701: Table 'test.table2' does not exist.", 
e.getMessage());
       }
 
       try {
         statement.executeQuery("count devices from table2");
         fail("Count devices shall fail for non-exist table");
       } catch (final Exception e) {
-        // Pass
+        assertEquals("701: Table 'test.table2' does not exist.", 
e.getMessage());
+      }
+
+      try {
+        statement.executeQuery("show devices from table0 where temperature = 
37.6");
+        fail("Show devices shall fail for measurement predicate");
+      } catch (final Exception e) {
+        assertEquals("701: Column 'temperature' cannot be resolved", 
e.getMessage());
+      }
+
+      try {
+        statement.executeQuery("count devices from table0 where a = 1");
+        fail("Count devices shall fail for non-exist column");
+      } catch (final Exception e) {
+        assertEquals("701: Column 'a' cannot be resolved", e.getMessage());
       }
 
       // Test fully qualified name
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
index 91c7ebda26b..4a0f96a15f4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
@@ -60,7 +60,9 @@ public class SchemaCountOperator<T extends ISchemaInfo> 
implements SourceOperato
   private TsBlock next; // next will be set only when done
 
   public SchemaCountOperator(
-      PlanNodeId sourceId, OperatorContext operatorContext, ISchemaSource<T> 
schemaSource) {
+      final PlanNodeId sourceId,
+      final OperatorContext operatorContext,
+      final ISchemaSource<T> schemaSource) {
     this.sourceId = sourceId;
     this.operatorContext = operatorContext;
     this.schemaSource = schemaSource;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DevicePredicateFilter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DevicePredicateFilter.java
new file mode 100644
index 00000000000..b0a07264337
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DevicePredicateFilter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.execution.operator.schema.source;
+
+import 
org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer;
+import 
org.apache.iotdb.db.queryengine.transformation.dag.column.leaf.LeafColumnTransformer;
+
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.read.common.block.TsBlock;
+
+import java.util.List;
+
+public class DevicePredicateFilter {
+  private final List<LeafColumnTransformer> filterLeafColumnTransformerList;
+  private final ColumnTransformer filterOutputTransformer;
+
+  public DevicePredicateFilter(
+      final List<LeafColumnTransformer> filterLeafColumnTransformerList,
+      final ColumnTransformer filterOutputTransformer) {
+    this.filterLeafColumnTransformerList = filterLeafColumnTransformerList;
+    this.filterOutputTransformer = filterOutputTransformer;
+  }
+
+  // Single row tsBlock
+  public boolean match(final TsBlock input) {
+    // feed Filter ColumnTransformer, including TimeStampColumnTransformer and 
constant
+    filterLeafColumnTransformerList.forEach(
+        leafColumnTransformer -> leafColumnTransformer.initFromTsBlock(input));
+    filterOutputTransformer.tryEvaluate();
+
+    final Column filterColumn = filterOutputTransformer.getColumn();
+    return !filterColumn.isNull(0) && filterColumn.getBoolean(0);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
index 66dcbd94436..e72412c5f11 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
@@ -23,7 +23,6 @@ import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.commons.schema.filter.SchemaFilter;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.INodeSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
@@ -102,20 +101,20 @@ public class SchemaSourceFactory {
   }
 
   public static ISchemaSource<IDeviceSchemaInfo> getTableDeviceFetchSource(
-      String database,
-      String tableName,
-      List<Object[]> deviceIdList,
-      List<ColumnHeader> columnHeaderList) {
+      final String database,
+      final String tableName,
+      final List<Object[]> deviceIdList,
+      final List<ColumnHeader> columnHeaderList) {
     return new TableDeviceFetchSource(database, tableName, deviceIdList, 
columnHeaderList);
   }
 
   public static ISchemaSource<IDeviceSchemaInfo> getTableDeviceQuerySource(
-      String database,
-      String tableName,
-      List<List<SchemaFilter>> idDeterminedFilterList,
-      Expression idFuzzyFilter,
-      List<ColumnHeader> columnHeaderList) {
+      final String database,
+      final String tableName,
+      final List<List<SchemaFilter>> idDeterminedFilterList,
+      final List<ColumnHeader> columnHeaderList,
+      final DevicePredicateFilter filter) {
     return new TableDeviceQuerySource(
-        database, tableName, idDeterminedFilterList, idFuzzyFilter, 
columnHeaderList);
+        database, tableName, idDeterminedFilterList, columnHeaderList, filter);
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java
index 13732733503..9a1aeb0e139 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java
@@ -27,22 +27,21 @@ import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
-import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.schema.ConvertSchemaPredicateToFilterVisitor;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl.ShowTableDevicesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.reader.ISchemaReader;
 import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.read.common.block.TsBlockBuilder;
 import org.apache.tsfile.utils.Binary;
 
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo> {
 
@@ -52,25 +51,20 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
 
   private final List<List<SchemaFilter>> idDeterminedPredicateList;
 
-  private final Expression idFuzzyPredicate;
-
   private final List<ColumnHeader> columnHeaderList;
-
-  private final TsTable table;
+  private final DevicePredicateFilter filter;
 
   public TableDeviceQuerySource(
       final String database,
       final String tableName,
       final List<List<SchemaFilter>> idDeterminedPredicateList,
-      final Expression idFuzzyPredicate,
-      final List<ColumnHeader> columnHeaderList) {
+      final List<ColumnHeader> columnHeaderList,
+      final DevicePredicateFilter filter) {
     this.database = database;
     this.tableName = tableName;
     this.idDeterminedPredicateList = idDeterminedPredicateList;
-    this.idFuzzyPredicate = idFuzzyPredicate;
     this.columnHeaderList = columnHeaderList;
-
-    this.table = DataNodeTableCache.getInstance().getTable(database, 
tableName);
+    this.filter = filter;
   }
 
   @Override
@@ -81,6 +75,9 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
       private ISchemaReader<IDeviceSchemaInfo> deviceReader;
       private Throwable throwable;
       private int index = 0;
+      private final List<TSDataType> dataTypes =
+          
columnHeaderList.stream().map(ColumnHeader::getColumnType).collect(Collectors.toList());
+      private IDeviceSchemaInfo next;
 
       @Override
       public boolean isSuccess() {
@@ -104,6 +101,16 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
 
       @Override
       public boolean hasNext() {
+        while (next == null && innerHasNext()) {
+          final IDeviceSchemaInfo temp = deviceReader.next();
+          if (match(temp)) {
+            next = temp;
+          }
+        }
+        return next != null;
+      }
+
+      private boolean innerHasNext() {
         try {
           if (throwable != null) {
             return false;
@@ -121,11 +128,7 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
           }
 
           while (index < devicePatternList.size()) {
-            deviceReader =
-                schemaRegion.getTableDeviceReader(
-                    new ShowTableDevicesPlan(
-                        devicePatternList.get(index),
-                        getExecutableIdFuzzyFilter(idFuzzyPredicate)));
+            deviceReader = 
schemaRegion.getTableDeviceReader(devicePatternList.get(index));
             index++;
             if (deviceReader.hasNext()) {
               return true;
@@ -144,7 +147,18 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
         if (!hasNext()) {
           throw new NoSuchElementException();
         }
-        return deviceReader.next();
+        final IDeviceSchemaInfo result = next;
+        next = null;
+        return result;
+      }
+
+      private boolean match(final IDeviceSchemaInfo deviceSchemaInfo) {
+        if (Objects.isNull(filter)) {
+          return true;
+        }
+        final TsBlockBuilder builder = new TsBlockBuilder(dataTypes);
+        transformToTsBlockColumns(deviceSchemaInfo, builder, database);
+        return filter.match(builder.build());
       }
 
       @Override
@@ -168,16 +182,6 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
         idDeterminedPredicateList);
   }
 
-  private SchemaFilter getExecutableIdFuzzyFilter(final Expression 
idFuzzyExpression) {
-    if (idFuzzyExpression == null) {
-      return null;
-    }
-    final ConvertSchemaPredicateToFilterVisitor visitor =
-        new ConvertSchemaPredicateToFilterVisitor();
-    return visitor.process(
-        idFuzzyExpression, new 
ConvertSchemaPredicateToFilterVisitor.Context(table));
-  }
-
   @Override
   public List<ColumnHeader> getInfoQueryColumnHeaders() {
     return columnHeaderList;
@@ -186,21 +190,30 @@ public class TableDeviceQuerySource implements 
ISchemaSource<IDeviceSchemaInfo>
   @Override
   public void transformToTsBlockColumns(
       final IDeviceSchemaInfo schemaInfo, final TsBlockBuilder builder, final 
String database) {
+    transformToTsBlockColumns(schemaInfo, builder, database, tableName, 
columnHeaderList, 3);
+  }
+
+  public static void transformToTsBlockColumns(
+      final IDeviceSchemaInfo schemaInfo,
+      final TsBlockBuilder builder,
+      final String database,
+      final String tableName,
+      final List<ColumnHeader> columnHeaderList,
+      int idIndex) {
     builder.getTimeColumnBuilder().writeLong(0L);
     int resultIndex = 0;
-    int idIndex = 0;
     final String[] pathNodes = schemaInfo.getRawNodes();
-    final TsTable table = 
DataNodeTableCache.getInstance().getTable(this.database, tableName);
+    final TsTable table = DataNodeTableCache.getInstance().getTable(database, 
tableName);
     TsTableColumnSchema columnSchema;
     for (final ColumnHeader columnHeader : columnHeaderList) {
       columnSchema = table.getColumnSchema(columnHeader.getColumnName());
       if (columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)) {
-        if (pathNodes.length <= idIndex + 3 || pathNodes[idIndex + 3] == null) 
{
+        if (pathNodes.length <= idIndex || pathNodes[idIndex] == null) {
           builder.getColumnBuilder(resultIndex).appendNull();
         } else {
           builder
               .getColumnBuilder(resultIndex)
-              .writeBinary(new Binary(pathNodes[idIndex + 3], 
TSFileConfig.STRING_CHARSET));
+              .writeBinary(new Binary(pathNodes[idIndex], 
TSFileConfig.STRING_CHARSET));
         }
         idIndex++;
       } else if 
(columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE)) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
index 4304d8ecf4c..665364b9ef7 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java
@@ -29,8 +29,10 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute.TableDistributedPlanGenerator;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute.TableDistributedPlanner;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice;
 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.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice;
 
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.read.common.block.TsBlock;
@@ -47,22 +49,22 @@ public class TableModelStatementMemorySourceVisitor
 
   @Override
   public StatementMemorySource visitNode(
-      Node node, TableModelStatementMemorySourceContext context) {
-    DatasetHeader datasetHeader = context.getAnalysis().getRespDatasetHeader();
+      final Node node, final TableModelStatementMemorySourceContext context) {
+    final DatasetHeader datasetHeader = 
context.getAnalysis().getRespDatasetHeader();
     return new StatementMemorySource(
         new TsBlock(0), datasetHeader == null ? EMPTY_HEADER : datasetHeader);
   }
 
   @Override
   public StatementMemorySource visitExplain(
-      Explain node, TableModelStatementMemorySourceContext context) {
+      final Explain node, final TableModelStatementMemorySourceContext 
context) {
     context.getAnalysis().setStatement(node.getStatement());
-    DatasetHeader header =
+    final DatasetHeader header =
         new DatasetHeader(
             Collections.singletonList(
                 new ColumnHeader(IoTDBConstant.COLUMN_DISTRIBUTION_PLAN, 
TSDataType.TEXT)),
             true);
-    LogicalQueryPlan logicalPlan =
+    final LogicalQueryPlan logicalPlan =
         new 
org.apache.iotdb.db.queryengine.plan.relational.planner.LogicalPlanner(
                 context.getQueryContext(),
                 LocalExecutionPlanner.getInstance().metadata,
@@ -73,14 +75,14 @@ public class TableModelStatementMemorySourceVisitor
       return new StatementMemorySource(new TsBlock(0), header);
     }
 
-    // generate table model distributed plan
-    TableDistributedPlanGenerator.PlanContext planContext =
+    // Generate table model distributed plan
+    final TableDistributedPlanGenerator.PlanContext planContext =
         new TableDistributedPlanGenerator.PlanContext();
-    PlanNode outputNodeWithExchange =
+    final PlanNode outputNodeWithExchange =
         new TableDistributedPlanner(context.getAnalysis(), logicalPlan, 
context.getQueryContext())
             .generateDistributedPlanWithOptimize(planContext);
 
-    List<String> lines =
+    final List<String> lines =
         outputNodeWithExchange.accept(
             new PlanGraphPrinter(),
             new PlanGraphPrinter.GraphContext(
@@ -88,4 +90,16 @@ public class TableModelStatementMemorySourceVisitor
 
     return getStatementMemorySource(header, lines);
   }
+
+  @Override
+  public StatementMemorySource visitShowDevice(
+      final ShowDevice node, final TableModelStatementMemorySourceContext 
context) {
+    return new StatementMemorySource(node.getTsBlock(), 
node.getDataSetHeader());
+  }
+
+  @Override
+  public StatementMemorySource visitCountDevice(
+      final CountDevice node, final TableModelStatementMemorySourceContext 
context) {
+    return new StatementMemorySource(node.getTsBlock(), 
node.getDataSetHeader());
+  }
 }
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 29086a7f6b7..232c5f61d2e 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
@@ -43,6 +43,7 @@ import 
org.apache.iotdb.db.queryengine.execution.operator.process.TableTopKOpera
 import 
org.apache.iotdb.db.queryengine.execution.operator.schema.CountMergeOperator;
 import 
org.apache.iotdb.db.queryengine.execution.operator.schema.SchemaCountOperator;
 import 
org.apache.iotdb.db.queryengine.execution.operator.schema.SchemaQueryScanOperator;
+import 
org.apache.iotdb.db.queryengine.execution.operator.schema.source.DevicePredicateFilter;
 import 
org.apache.iotdb.db.queryengine.execution.operator.schema.source.SchemaSourceFactory;
 import 
org.apache.iotdb.db.queryengine.execution.operator.sink.IdentitySinkOperator;
 import 
org.apache.iotdb.db.queryengine.execution.operator.source.AlignedSeriesScanOperator;
@@ -93,11 +94,13 @@ import javax.validation.constraints.NotNull;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -771,42 +774,61 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
   @Override
   public Operator visitTableDeviceQueryScan(
       final TableDeviceQueryScanNode node, final LocalExecutionPlanContext 
context) {
-    final OperatorContext operatorContext =
+    // Query scan use filterNode directly
+    return new SchemaQueryScanOperator<>(
+        node.getPlanNodeId(),
         context
             .getDriverContext()
             .addOperatorContext(
                 context.getNextOperatorId(),
                 node.getPlanNodeId(),
-                SchemaQueryScanOperator.class.getSimpleName());
-    return new SchemaQueryScanOperator<>(
-        node.getPlanNodeId(),
-        operatorContext,
+                SchemaQueryScanOperator.class.getSimpleName()),
         SchemaSourceFactory.getTableDeviceQuerySource(
             node.getDatabase(),
             node.getTableName(),
             node.getIdDeterminedFilterList(),
-            node.getIdFuzzyPredicate(),
-            node.getColumnHeaderList()));
+            node.getColumnHeaderList(),
+            null));
   }
 
   @Override
   public Operator visitTableDeviceQueryCount(
       final TableDeviceQueryCountNode node, final LocalExecutionPlanContext 
context) {
-    final OperatorContext operatorContext =
+    // In "count" we have to reuse filter operator per "next"
+    final List<LeafColumnTransformer> filterLeafColumnTransformerList = new 
ArrayList<>();
+    return new SchemaCountOperator<>(
+        node.getPlanNodeId(),
         context
             .getDriverContext()
             .addOperatorContext(
                 context.getNextOperatorId(),
                 node.getPlanNodeId(),
-                SchemaCountOperator.class.getSimpleName());
-    return new SchemaCountOperator<>(
-        node.getPlanNodeId(),
-        operatorContext,
+                SchemaCountOperator.class.getSimpleName()),
         SchemaSourceFactory.getTableDeviceQuerySource(
             node.getDatabase(),
             node.getTableName(),
             node.getIdDeterminedFilterList(),
-            node.getIdFuzzyPredicate(),
-            node.getColumnHeaderList()));
+            node.getColumnHeaderList(),
+            Objects.nonNull(node.getIdFuzzyPredicate())
+                ? new DevicePredicateFilter(
+                    filterLeafColumnTransformerList,
+                    new ColumnTransformerBuilder()
+                        .process(
+                            node.getIdFuzzyPredicate(),
+                            new ColumnTransformerBuilder.Context(
+                                context
+                                    .getDriverContext()
+                                    .getFragmentInstanceContext()
+                                    .getSessionInfo(),
+                                filterLeafColumnTransformerList,
+                                makeLayout(Collections.singletonList(node)),
+                                new HashMap<>(),
+                                ImmutableMap.of(),
+                                ImmutableList.of(),
+                                ImmutableList.of(),
+                                0,
+                                context.getTypeProvider(),
+                                metadata)))
+                : null));
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceFetchNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceFetchNode.java
index 435fadacb82..d598a351cb9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceFetchNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceFetchNode.java
@@ -34,7 +34,6 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
-import java.util.stream.Collectors;
 
 public class TableDeviceFetchNode extends TableDeviceSourceNode {
 
@@ -75,11 +74,6 @@ public class TableDeviceFetchNode extends 
TableDeviceSourceNode {
         schemaRegionReplicaSet);
   }
 
-  @Override
-  public List<String> getOutputColumnNames() {
-    return 
columnHeaderList.stream().map(ColumnHeader::getColumnName).collect(Collectors.toList());
-  }
-
   @Override
   protected void serializeAttributes(final ByteBuffer byteBuffer) {
     PlanNodeType.TABLE_DEVICE_FETCH.serialize(byteBuffer);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceQueryCountNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceQueryCountNode.java
index a631e91b063..b09996bf5bf 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceQueryCountNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TableDeviceQueryCountNode.java
@@ -29,8 +29,11 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 import java.util.List;
 
+import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice.COUNT_DEVICE_HEADER_STRING;
+
 public class TableDeviceQueryCountNode extends AbstractTableDeviceQueryNode {
 
   public TableDeviceQueryCountNode(
@@ -51,6 +54,11 @@ public class TableDeviceQueryCountNode extends 
AbstractTableDeviceQueryNode {
         schemaRegionReplicaSet);
   }
 
+  @Override
+  public List<String> getOutputColumnNames() {
+    return Collections.singletonList(COUNT_DEVICE_HEADER_STRING);
+  }
+
   @Override
   public <R, C> R accept(final PlanVisitor<R, C> visitor, final C context) {
     return visitor.visitTableDeviceQueryCount(this, context);
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 1d7e5bd5abe..7093cbf08dd 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
@@ -19,7 +19,9 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 
+import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
@@ -32,8 +34,12 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.PlannerContext;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.ScopeAware;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.TranslationMap;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AbstractQueryDeviceWithCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AliasedRelation;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AllColumns;
@@ -110,6 +116,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.With;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.WithQuery;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.WrappedInsertStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertBaseStatement;
+import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
@@ -128,6 +135,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.OptionalLong;
 import java.util.Set;
@@ -1508,7 +1516,7 @@ public class StatementAnalyzer {
       analysis.addEmptyColumnReferencesForTable(accessControl, 
sessionContext.getIdentity(), name);
 
       ImmutableList.Builder<Field> fields = ImmutableList.builder();
-      fields.addAll(analyzeTableOutputFields(table, name, tableSchema.get()));
+      fields.addAll(analyzeTableOutputFields(table.getName(), name, 
tableSchema.get()));
 
       //      boolean addRowIdColumn = updateKind.isPresent();
       //
@@ -1605,14 +1613,16 @@ public class StatementAnalyzer {
     }
 
     private List<Field> analyzeTableOutputFields(
-        Table table, QualifiedObjectName tableName, TableSchema tableSchema) {
+        final QualifiedName relationAlias,
+        final QualifiedObjectName tableName,
+        final TableSchema tableSchema) {
       // TODO: discover columns lazily based on where they are needed (to 
support connectors that
       // can't enumerate all tables)
       ImmutableList.Builder<Field> fields = ImmutableList.builder();
       for (ColumnSchema column : tableSchema.getColumns()) {
         Field field =
             Field.newQualified(
-                table.getName(),
+                relationAlias,
                 Optional.of(column.getName()),
                 column.getType(),
                 column.getColumnCategory(),
@@ -2496,15 +2506,87 @@ public class StatementAnalyzer {
 
     @Override
     protected Scope visitShowDevice(final ShowDevice node, final 
Optional<Scope> context) {
-      node.parseQualifiedName(sessionContext);
+      analyzeQueryDevice(node, context);
       return null;
     }
 
     @Override
     protected Scope visitCountDevice(final CountDevice node, final 
Optional<Scope> context) {
-      node.parseQualifiedName(sessionContext);
+      analyzeQueryDevice(node, context);
       return null;
     }
+
+    private void analyzeQueryDevice(
+        final AbstractQueryDeviceWithCache node, final Optional<Scope> 
context) {
+      node.parseQualifiedName(sessionContext);
+      final String database = node.getDatabase();
+      final String tableName = node.getTableName();
+
+      if (Objects.isNull(database)) {
+        throw new SemanticException("The database must be set before show 
devices.");
+      }
+
+      final TsTable table = 
DataNodeTableCache.getInstance().getTable(database, tableName);
+
+      if (Objects.isNull(table)) {
+        throw new SemanticException(
+            String.format("Table '%s.%s' does not exist.", database, 
tableName));
+      }
+
+      final List<String> attributeList =
+          table.getColumnList().stream()
+              .filter(
+                  columnSchema ->
+                      
columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE))
+              .map(TsTableColumnSchema::getColumnName)
+              .collect(Collectors.toList());
+
+      node.setColumnHeaderList();
+      if (Objects.nonNull(node.getRawExpression())) {
+        final QualifiedObjectName name = new QualifiedObjectName(database, 
tableName);
+        final Optional<TableSchema> tableSchema = 
metadata.getTableSchema(sessionContext, name);
+        // This can only be a table
+        if (!tableSchema.isPresent()) {
+          throw new SemanticException(String.format("Table '%s' does not 
exist", name));
+        }
+
+        final TableSchema originalSchema = tableSchema.get();
+        final ImmutableList.Builder<Field> fields = ImmutableList.builder();
+        fields.addAll(
+            analyzeTableOutputFields(
+                node.getName(),
+                name,
+                new TableSchema(
+                    originalSchema.getTableName(),
+                    originalSchema.getColumns().stream()
+                        .filter(
+                            columnSchema ->
+                                columnSchema.getColumnCategory() == 
TsTableColumnCategory.ID
+                                    || columnSchema.getColumnCategory()
+                                        == TsTableColumnCategory.ATTRIBUTE)
+                        .collect(Collectors.toList()))));
+        final List<Field> fieldList = fields.build();
+        final Scope scope = createAndAssignScope(node, context, fieldList);
+        analyzeExpression(node.getRawExpression(), scope);
+        node.setRawExpression(
+            new TranslationMap(
+                    Optional.empty(),
+                    scope,
+                    analysis,
+                    fieldList.stream()
+                        .map(field -> Symbol.of(field.getName().orElse(null)))
+                        .collect(Collectors.toList()),
+                    new PlannerContext(metadata, null))
+                .rewrite(node.getRawExpression()));
+      }
+      if (!node.parseRawExpression(table, attributeList, queryContext)) {
+        // Cache hit
+        // Currently we disallow "Or" filter for precise get, thus if it hit 
cache
+        // it'll be only one device
+        // TODO: Ensure the disjointness of expressions and allow Or filter
+        analysis.setFinishQueryAfterAnalyze();
+      }
+    }
   }
 
   private static boolean hasScopeAsLocalParent(Scope root, Scope parent) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/CheckSchemaPredicateVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/CheckSchemaPredicateVisitor.java
index 379026dbcd4..32db3f51ff0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/CheckSchemaPredicateVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/CheckSchemaPredicateVisitor.java
@@ -21,6 +21,7 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.schem
 
 import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicateVisitor;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.BetweenPredicate;
@@ -42,6 +43,8 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.TableExpressionTy
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Objects;
+
 // Return whether input expression can not be bounded to a single ID
 public class CheckSchemaPredicateVisitor
     extends PredicateVisitor<Boolean, CheckSchemaPredicateVisitor.Context> {
@@ -81,6 +84,10 @@ public class CheckSchemaPredicateVisitor
       }
       return true;
     }
+    // TODO: improve the distinct result set detection logic
+    if (context.isDirectDeviceQuery) {
+      return true;
+    }
     return node.getTerms().stream().anyMatch(predicate -> 
predicate.accept(this, context));
   }
 
@@ -133,11 +140,11 @@ public class CheckSchemaPredicateVisitor
   }
 
   private boolean processColumn(final Expression node, final Context context) {
-    return context
-        .table
-        
.getColumnSchema(node.accept(ExtractPredicateColumnNameVisitor.getInstance(), 
null))
-        .getColumnCategory()
-        .equals(TsTableColumnCategory.ATTRIBUTE);
+    final TsTableColumnSchema schema =
+        context.table.getColumnSchema(
+            node.accept(ExtractPredicateColumnNameVisitor.getInstance(), 
null));
+    return Objects.isNull(schema)
+        || schema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE);
   }
 
   public static class Context {
@@ -145,10 +152,15 @@ public class CheckSchemaPredicateVisitor
 
     // For query performance analyze
     private final MPPQueryContext queryContext;
+    private final boolean isDirectDeviceQuery;
 
-    public Context(final TsTable table, final MPPQueryContext queryContext) {
+    public Context(
+        final TsTable table,
+        final MPPQueryContext queryContext,
+        final boolean isDirectDeviceQuery) {
       this.table = table;
       this.queryContext = queryContext;
+      this.isDirectDeviceQuery = isDirectDeviceQuery;
     }
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ExtractPredicateColumnNameVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ExtractPredicateColumnNameVisitor.java
index fb2cc60f619..370c9287723 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ExtractPredicateColumnNameVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ExtractPredicateColumnNameVisitor.java
@@ -72,18 +72,25 @@ public class ExtractPredicateColumnNameVisitor extends 
PredicateVisitor<String,
     final String columnName;
     if (node.getLeft() instanceof Literal) {
       if (!(node.getRight() instanceof SymbolReference)) {
-        throw new IllegalStateException("Can only be SymbolReference, now is " 
+ node.getRight());
+        // TODO: implement schema function filter and parse some function call 
into id determined
+        // filter
+        return null;
       }
       columnName = ((SymbolReference) (node.getRight())).getName();
     } else {
       if (!(node.getLeft() instanceof SymbolReference)) {
-        throw new IllegalStateException("Can only be SymbolReference, now is " 
+ node.getLeft());
+        return null;
       }
       columnName = ((SymbolReference) (node.getLeft())).getName();
     }
     return columnName;
   }
 
+  @Override
+  protected String visitSymbolReference(final SymbolReference node, final Void 
context) {
+    return node.getName();
+  }
+
   @Override
   protected String visitSimpleCaseExpression(final SimpleCaseExpression node, 
final Void context) {
     return null;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
index 3366a48b6b5..2872ea9ea9e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
@@ -66,16 +66,16 @@ public class MetadataUtil {
   }
 
   public static QualifiedObjectName createQualifiedObjectName(
-      SessionInfo session, QualifiedName name) {
+      final SessionInfo session, final QualifiedName name) {
     requireNonNull(session, "session is null");
     requireNonNull(name, "name is null");
     if (name.getParts().size() > 2) {
       throw new SemanticException(String.format("Too many dots in table name: 
%s", name));
     }
 
-    List<String> parts = Lists.reverse(name.getParts());
-    String objectName = parts.get(0);
-    String databaseName =
+    final List<String> parts = Lists.reverse(name.getParts());
+    final String objectName = parts.get(0);
+    final String databaseName =
         (parts.size() > 1)
             ? parts.get(1)
             : session
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java
index 1880e92eee9..b470a2465b1 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java
@@ -55,12 +55,13 @@ public class SchemaPredicateUtil {
   static Pair<List<Expression>, List<Expression>> 
separateIdDeterminedPredicate(
       final List<Expression> expressionList,
       final TsTable table,
-      final MPPQueryContext queryContext) {
+      final MPPQueryContext queryContext,
+      final boolean isDirectDeviceQuery) {
     final List<Expression> idDeterminedList = new ArrayList<>();
     final List<Expression> idFuzzyList = new ArrayList<>();
     final CheckSchemaPredicateVisitor visitor = new 
CheckSchemaPredicateVisitor();
     final CheckSchemaPredicateVisitor.Context context =
-        new CheckSchemaPredicateVisitor.Context(table, queryContext);
+        new CheckSchemaPredicateVisitor.Context(table, queryContext, 
isDirectDeviceQuery);
     for (final Expression expression : expressionList) {
       if (expression == null) {
         continue;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
index 5e7b1833a76..fa95e78882b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
@@ -39,6 +39,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.schema
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableDeviceId;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableDeviceSchemaCache;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AbstractTraverseDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FetchDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice;
@@ -168,14 +169,46 @@ public class TableDeviceSchemaFetcher {
       final List<String> attributeColumns,
       final MPPQueryContext queryContext) {
     final List<DeviceEntry> deviceEntryList = new ArrayList<>();
-
+    final ShowDevice statement = new ShowDevice(database, table);
     final TsTable tableInstance = 
DataNodeTableCache.getInstance().getTable(database, table);
     if (tableInstance == null) {
       throw new SemanticException(String.format("Table '%s.%s' does not 
exist", database, table));
     }
+
+    if (parseFilter4TraverseDevice(
+        database,
+        tableInstance,
+        expressionList,
+        statement,
+        deviceEntryList,
+        attributeColumns,
+        queryContext,
+        false)) {
+      fetchMissingDeviceSchemaForQuery(
+          database, tableInstance, attributeColumns, statement, 
deviceEntryList, queryContext);
+    }
+
+    // TODO table metadata:  implement deduplicate during schemaRegion 
execution
+    // TODO table metadata:  need further process on input predicates and 
transform them into
+    // disjoint sets
+    final Set<DeviceEntry> set = new LinkedHashSet<>(deviceEntryList);
+    return new ArrayList<>(set);
+  }
+
+  // Used by show/count device and update device.
+  // Update device will not access cache
+  public boolean parseFilter4TraverseDevice(
+      final String database,
+      final TsTable tableInstance,
+      final List<Expression> expressionList,
+      final AbstractTraverseDevice statement,
+      final List<DeviceEntry> deviceEntryList,
+      final List<String> attributeColumns,
+      final MPPQueryContext queryContext,
+      final boolean isDirectDeviceQuery) {
     final Pair<List<Expression>, List<Expression>> separatedExpression =
         SchemaPredicateUtil.separateIdDeterminedPredicate(
-            expressionList, tableInstance, queryContext);
+            expressionList, tableInstance, queryContext, isDirectDeviceQuery);
     final List<Expression> idDeterminedPredicateList = 
separatedExpression.left; // and-concat
     final List<Expression> idFuzzyPredicateList = separatedExpression.right; 
// and-concat
 
@@ -220,7 +253,8 @@ public class TableDeviceSchemaFetcher {
             index2FilterMapList.get(index),
             o -> fuzzyFilter == null || filterVisitor.process(fuzzyFilter, o),
             attributeColumns,
-            fetchPaths)) {
+            fetchPaths,
+            isDirectDeviceQuery)) {
           idSingleMatchPredicateNotInCache.add(index);
         }
       }
@@ -253,25 +287,15 @@ public class TableDeviceSchemaFetcher {
           }
         }
       }
-      fetchMissingDeviceSchemaForQuery(
-          database,
-          tableInstance,
-          attributeColumns,
-          idPredicateForFetch,
-          compactedIdFuzzyPredicate,
-          deviceEntryList,
-          fetchPaths,
-          queryContext);
+      statement.setIdDeterminedFilterList(idPredicateForFetch);
+      statement.setIdFuzzyPredicate(compactedIdFuzzyPredicate);
+      statement.setPartitionKeyList(fetchPaths);
+      return true;
     }
-
-    // TODO table metadata:  implement deduplicate during schemaRegion 
execution
-    // TODO table metadata:  need further process on input predicates and 
transform them into
-    // disjoint sets
-    final Set<DeviceEntry> set = new LinkedHashSet<>(deviceEntryList);
-    return new ArrayList<>(set);
+    return false;
   }
 
-  // return whether all of required info of current device is in cache
+  // Return whether all of required info of current device is in cache
   private boolean tryGetDeviceInCache(
       final List<DeviceEntry> deviceEntryList,
       final String database,
@@ -279,7 +303,8 @@ public class TableDeviceSchemaFetcher {
       final Map<Integer, List<SchemaFilter>> idFilters,
       final Predicate<DeviceEntry> check,
       final List<String> attributeColumns,
-      final List<IDeviceID> fetchPaths) {
+      final List<IDeviceID> fetchPaths,
+      final boolean isDirectDeviceQuery) {
     String[] idValues = new String[tableInstance.getIdNums()];
     for (final List<SchemaFilter> schemaFilters : idFilters.values()) {
       final IdFilter idFilter = (IdFilter) schemaFilters.get(0);
@@ -290,9 +315,11 @@ public class TableDeviceSchemaFetcher {
     idValues = (String[]) truncateTailingNull(idValues);
     final Map<String, String> attributeMap =
         cache.getDeviceAttribute(database, tableInstance.getTableName(), 
idValues);
+
+    final IDeviceID deviceID = convertIdValuesToDeviceID(idValues, 
tableInstance);
     if (attributeMap == null) {
       if (Objects.nonNull(fetchPaths)) {
-        fetchPaths.add(convertIdValuesToDeviceID(idValues, tableInstance));
+        fetchPaths.add(deviceID);
       }
       return false;
     }
@@ -301,19 +328,23 @@ public class TableDeviceSchemaFetcher {
       if (!attributeMap.containsKey(attributeKey)) {
         // The attributes may be updated and the cache entry is stale
         if (Objects.nonNull(fetchPaths)) {
-          fetchPaths.add(convertIdValuesToDeviceID(idValues, tableInstance));
+          fetchPaths.add(deviceID);
         }
         return false;
       }
       attributeValues.add(attributeMap.get(attributeKey));
     }
 
-    final DeviceEntry deviceEntry =
-        new DeviceEntry(convertIdValuesToDeviceID(idValues, tableInstance), 
attributeValues);
+    final DeviceEntry deviceEntry = new DeviceEntry(deviceID, attributeValues);
     // TODO table metadata: process cases that selected attr columns different 
from those used for
     // predicate
     if (check.test(deviceEntry)) {
       deviceEntryList.add(deviceEntry);
+      // If we partially hit cache in direct device query, we must fetch for 
all the predicates
+      // because now we do not support combining memory source and other 
sources
+      if (isDirectDeviceQuery) {
+        fetchPaths.add(deviceID);
+      }
     }
     return true;
   }
@@ -331,17 +362,13 @@ public class TableDeviceSchemaFetcher {
       final String database,
       final TsTable tableInstance,
       final List<String> attributeColumns,
-      final List<List<SchemaFilter>> idDeterminedFilterList,
-      final Expression idFuzzyPredicate,
+      final ShowDevice statement,
       final List<DeviceEntry> deviceEntryList,
-      final List<IDeviceID> fetchPaths,
       final MPPQueryContext mppQueryContext) {
 
     final String table = tableInstance.getTableName();
 
     final long queryId = SessionManager.getInstance().requestQueryId();
-    final ShowDevice statement =
-        new ShowDevice(database, table, idDeterminedFilterList, 
idFuzzyPredicate, fetchPaths);
     final ExecutionResult executionResult =
         coordinator.executeForTableModel(
             statement,
@@ -386,7 +413,7 @@ public class TableDeviceSchemaFetcher {
               attributeMap, nodes, 1, columnHeaderList, columns, 
tableInstance, i);
           nodes = (String[]) truncateTailingNull(nodes);
           final IDeviceID deviceID = 
IDeviceID.Factory.DEFAULT_FACTORY.create(nodes);
-          DeviceEntry deviceEntry =
+          final DeviceEntry deviceEntry =
               new DeviceEntry(
                   deviceID,
                   
attributeColumns.stream().map(attributeMap::get).collect(Collectors.toList()));
@@ -394,7 +421,7 @@ public class TableDeviceSchemaFetcher {
           deviceEntryList.add(deviceEntry);
           // Only cache those exact device query
           // Fetch paths is null iff there are fuzzy queries related to id 
columns
-          if (Objects.nonNull(fetchPaths)) {
+          if (Objects.nonNull(statement.getPartitionKeyList())) {
             cache.put(database, table, Arrays.copyOfRange(nodes, 1, 
nodes.length), attributeMap);
           }
         }
@@ -408,15 +435,15 @@ public class TableDeviceSchemaFetcher {
   }
 
   private void constructNodsArrayAndAttributeMap(
-      Map<String, String> attributeMap,
-      String[] nodes,
+      final Map<String, String> attributeMap,
+      final String[] nodes,
       int startIndex,
-      List<ColumnHeader> columnHeaderList,
-      Column[] columns,
-      TsTable tableInstance,
-      int rowIndex) {
+      final List<ColumnHeader> columnHeaderList,
+      final Column[] columns,
+      final TsTable tableInstance,
+      final int rowIndex) {
     for (int j = 0; j < columnHeaderList.size(); j++) {
-      TsTableColumnSchema columnSchema =
+      final TsTableColumnSchema columnSchema =
           
tableInstance.getColumnSchema(columnHeaderList.get(j).getColumnName());
       // means that TsTable tableInstance which previously fetched is 
outdated, but it's ok that we
       // ignore that newly added column here
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 0024d886d83..d5bb6458c9a 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
@@ -15,10 +15,7 @@
 package org.apache.iotdb.db.queryengine.plan.relational.planner;
 
 import org.apache.iotdb.commons.partition.SchemaPartition;
-import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
-import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.commons.utils.TestOnly;
-import org.apache.iotdb.db.exception.sql.SemanticException;
 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;
@@ -41,7 +38,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.LogicalOptimizeFactory;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PlanOptimizer;
-import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AbstractQueryDevice;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AbstractQueryDeviceWithCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Explain;
@@ -52,21 +49,19 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Table;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.WrappedStatement;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
-import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import org.apache.tsfile.enums.TSDataType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 
 import static java.util.Objects.requireNonNull;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice.getDeviceColumnHeaderList;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
 
 public class LogicalPlanner {
@@ -237,7 +232,7 @@ public class LogicalPlanner {
 
   private PlanNode planFetchDevice(final FetchDevice statement, final Analysis 
analysis) {
     final List<ColumnHeader> columnHeaderList =
-        getColumnHeaderList(statement.getDatabase(), statement.getTableName());
+        getDeviceColumnHeaderList(statement.getDatabase(), 
statement.getTableName());
 
     analysis.setRespDatasetHeader(new DatasetHeader(columnHeaderList, true));
 
@@ -262,22 +257,16 @@ public class LogicalPlanner {
   }
 
   private PlanNode planShowDevice(final ShowDevice statement, final Analysis 
analysis) {
-    final String database = planQueryDevice(statement, analysis);
-    List<ColumnHeader> columnHeaderList = null;
-    if (!analysis.isFailed()) {
-      columnHeaderList = getColumnHeaderList(database, 
statement.getTableName());
-      analysis.setRespDatasetHeader(
-          new DatasetHeader(getColumnHeaderList(database, 
statement.getTableName()), true));
-    }
+    planQueryDevice(statement, analysis);
 
     final TableDeviceQueryScanNode node =
         new TableDeviceQueryScanNode(
             queryContext.getQueryId().genPlanNodeId(),
-            database,
+            statement.getDatabase(),
             statement.getTableName(),
             statement.getIdDeterminedFilterList(),
             null,
-            columnHeaderList,
+            statement.getColumnHeaderList(),
             null);
     return Objects.nonNull(statement.getIdFuzzyPredicate())
         ? new FilterNode(
@@ -286,19 +275,16 @@ public class LogicalPlanner {
   }
 
   private PlanNode planCountDevice(final CountDevice statement, final Analysis 
analysis) {
-    final String database = planQueryDevice(statement, analysis);
-    final List<ColumnHeader> columnHeaderList =
-        Collections.singletonList(new ColumnHeader("count(devices)", 
TSDataType.INT64));
-    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaderList, true));
+    planQueryDevice(statement, analysis);
 
     final TableDeviceQueryCountNode node =
         new TableDeviceQueryCountNode(
             queryContext.getQueryId().genPlanNodeId(),
-            database,
+            statement.getDatabase(),
             statement.getTableName(),
             statement.getIdDeterminedFilterList(),
             statement.getIdFuzzyPredicate(),
-            columnHeaderList,
+            statement.getColumnHeaderList(),
             null);
 
     final CountSchemaMergeNode countMergeNode =
@@ -307,15 +293,9 @@ public class LogicalPlanner {
     return countMergeNode;
   }
 
-  private String planQueryDevice(final AbstractQueryDevice statement, final 
Analysis analysis) {
-    final String database =
-        Objects.isNull(statement.getDatabase())
-            ? analysis.getDatabaseName()
-            : statement.getDatabase();
-
-    if (Objects.isNull(database)) {
-      throw new SemanticException("The database must be set before show 
devices.");
-    }
+  private void planQueryDevice(
+      final AbstractQueryDeviceWithCache statement, final Analysis analysis) {
+    final String database = statement.getDatabase();
 
     final SchemaPartition schemaPartition =
         statement.isIdDetermined()
@@ -327,27 +307,9 @@ public class LogicalPlanner {
       analysis.setFinishQueryAfterAnalyze();
     }
 
-    if (Objects.isNull(
-        DataNodeTableCache.getInstance().getTable(database, 
statement.getTableName()))) {
-      throw new SemanticException(
-          String.format("Table '%s.%s' does not exist.", database, 
statement.getTableName()));
-    }
-    return database;
-  }
-
-  private List<ColumnHeader> getColumnHeaderList(final String database, final 
String tableName) {
-    final List<TsTableColumnSchema> columnSchemaList =
-        DataNodeTableCache.getInstance().getTable(database, 
tableName).getColumnList();
-
-    final List<ColumnHeader> columnHeaderList = new 
ArrayList<>(columnSchemaList.size());
-    for (final TsTableColumnSchema columnSchema : columnSchemaList) {
-      if (columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)
-          || 
columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE)) {
-        columnHeaderList.add(
-            new ColumnHeader(columnSchema.getColumnName(), 
columnSchema.getDataType()));
-      }
+    if (!analysis.isFailed()) {
+      analysis.setRespDatasetHeader(statement.getDataSetHeader());
     }
-    return columnHeaderList;
   }
 
   private enum Stage {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelQueryFragmentPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelQueryFragmentPlanner.java
index 5327a4b690f..b2f8334b4f8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelQueryFragmentPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelQueryFragmentPlanner.java
@@ -32,6 +32,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ExchangeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.sink.MultiChildrenSinkNode;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Query;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement;
@@ -141,7 +142,9 @@ public class TableModelQueryFragmentPlanner {
         });
 
     final Statement statement = analysis.getStatement();
-    if (statement instanceof Query || statement instanceof ShowDevice) {
+    if (statement instanceof Query
+        || statement instanceof ShowDevice
+        || statement instanceof CountDevice) {
       
fragmentInstance.getFragment().generateTableModelTypeProvider(queryContext.getTypeProvider());
     }
     instanceMap.putIfAbsent(fragment.getId(), fragmentInstance);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
index 29fa48400b4..deb6678d4c6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java
@@ -17,6 +17,9 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner.distribute;
 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.SimplePlanVisitor;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.read.AbstractTableDeviceQueryNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.read.CountSchemaMergeNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.read.TableDeviceQueryCountNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.read.TableDeviceQueryScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ExchangeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.sink.IdentitySinkNode;
@@ -34,12 +37,15 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNod
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.TopKNode;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.read.common.type.BooleanType;
 import org.apache.tsfile.read.common.type.TypeFactory;
 
 import java.util.HashMap;
 import java.util.Map;
 
+import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice.COUNT_DEVICE_HEADER_STRING;
+
 public class TableModelTypeProviderExtractor {
 
   private TableModelTypeProviderExtractor() {}
@@ -84,8 +90,26 @@ public class TableModelTypeProviderExtractor {
       return null;
     }
 
+    @Override
+    public Void visitCountMerge(final CountSchemaMergeNode node, final Void 
context) {
+      beTypeProvider.putTableModelType(
+          new Symbol(COUNT_DEVICE_HEADER_STRING), 
TypeFactory.getType(TSDataType.INT64));
+      node.getChildren().forEach(schemaCount -> schemaCount.accept(this, 
context));
+      return null;
+    }
+
     @Override
     public Void visitTableDeviceQueryScan(final TableDeviceQueryScanNode node, 
final Void context) {
+      return visitAbstractTableDeviceQueryNode(node);
+    }
+
+    @Override
+    public Void visitTableDeviceQueryCount(
+        final TableDeviceQueryCountNode node, final Void context) {
+      return visitAbstractTableDeviceQueryNode(node);
+    }
+
+    private Void visitAbstractTableDeviceQueryNode(final 
AbstractTableDeviceQueryNode node) {
       node.getColumnHeaderList()
           .forEach(
               columnHeader ->
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDeviceWithCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDeviceWithCache.java
new file mode 100644
index 00000000000..94fe965fe4a
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDeviceWithCache.java
@@ -0,0 +1,103 @@
+/*
+ * 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.relational.sql.ast;
+
+import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
+import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.impl.ShowDevicesResult;
+import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
+
+import org.apache.tsfile.read.common.block.TsBlock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowDevice.getDeviceColumnHeaderList;
+
+public abstract class AbstractQueryDeviceWithCache extends 
AbstractTraverseDevice {
+
+  // For query devices fully in cache
+  protected List<ShowDevicesResult> results = new ArrayList<>();
+
+  // The "CountDevice"'s column header list is the same as the device's header
+  // to help reuse filter operator
+  protected List<ColumnHeader> columnHeaderList;
+
+  protected AbstractQueryDeviceWithCache(final QualifiedName name, final 
Expression rawExpression) {
+    super(name, rawExpression);
+  }
+
+  protected AbstractQueryDeviceWithCache(final String database, final String 
tableName) {
+    super(database, tableName);
+  }
+
+  public boolean parseRawExpression(
+      final TsTable tableInstance,
+      final List<String> attributeColumns,
+      final MPPQueryContext context) {
+    if (Objects.isNull(rawExpression)) {
+      return true;
+    }
+    final List<DeviceEntry> entries = new ArrayList<>();
+    final boolean needFetch =
+        super.parseRawExpression(entries, tableInstance, attributeColumns, 
context);
+    if (!needFetch) {
+      results =
+          entries.stream()
+              .map(
+                  deviceEntry ->
+                      ShowDevicesResult.convertDeviceEntry2ShowDeviceResult(
+                          deviceEntry, attributeColumns))
+              .collect(Collectors.toList());
+    }
+    return needFetch;
+  }
+
+  public List<ColumnHeader> getColumnHeaderList() {
+    return columnHeaderList;
+  }
+
+  public void setColumnHeaderList() {
+    this.columnHeaderList = getDeviceColumnHeaderList(database, tableName);
+  }
+
+  public static List<ColumnHeader> getDeviceColumnHeaderList(
+      final String database, final String tableName) {
+    return DataNodeTableCache.getInstance().getTable(database, 
tableName).getColumnList().stream()
+        .filter(
+            columnSchema ->
+                
columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)
+                    || 
columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE))
+        .map(
+            columnSchema ->
+                new ColumnHeader(columnSchema.getColumnName(), 
columnSchema.getDataType()))
+        .collect(Collectors.toList());
+  }
+
+  public abstract DatasetHeader getDataSetHeader();
+
+  public abstract TsBlock getTsBlock();
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDevice.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractTraverseDevice.java
similarity index 66%
rename from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDevice.java
rename to 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractTraverseDevice.java
index eeef4e8b6e8..dd0d77194a9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractQueryDevice.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AbstractTraverseDevice.java
@@ -20,9 +20,14 @@
 package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
 
 import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.MetadataUtil;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableDeviceSchemaFetcher;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExtractCommonPredicatesExpressionRewriter;
 
 import org.apache.tsfile.file.metadata.IDeviceID;
 
@@ -31,17 +36,16 @@ import java.util.List;
 import java.util.Objects;
 
 // TODO table metadata: reuse query distinct logic
-public abstract class AbstractQueryDevice extends Statement {
+public abstract class AbstractTraverseDevice extends Statement {
 
-  private String database;
+  protected String database;
 
-  private String tableName;
+  protected String tableName;
 
   // Temporary
   private QualifiedName name;
 
-  // Currently unused, shall be parsed into idDeterminedPredicateList and 
idFuzzyPredicate on demand
-  private Expression rawExpression;
+  protected Expression rawExpression;
 
   /**
    * The outer list represents the OR relation between different expression 
lists.
@@ -59,25 +63,16 @@ public abstract class AbstractQueryDevice extends Statement 
{
   private List<IDeviceID> partitionKeyList;
 
   // For sql-input show device usage
-  protected AbstractQueryDevice(final QualifiedName name, final Expression 
rawExpression) {
+  protected AbstractTraverseDevice(final QualifiedName name, final Expression 
rawExpression) {
     super(null);
     this.name = name;
     this.rawExpression = rawExpression;
   }
 
-  // For device fetch serving data query
-  protected AbstractQueryDevice(
-      final String database,
-      final String tableName,
-      final List<List<SchemaFilter>> idDeterminedFilterList,
-      final Expression idFuzzyFilterList,
-      final List<IDeviceID> partitionKeyList) {
+  protected AbstractTraverseDevice(final String database, final String 
tableName) {
     super(null);
     this.database = database;
     this.tableName = tableName;
-    this.idDeterminedFilterList = idDeterminedFilterList;
-    this.idFuzzyPredicate = idFuzzyFilterList;
-    this.partitionKeyList = partitionKeyList;
   }
 
   public void parseQualifiedName(final SessionInfo sessionInfo) {
@@ -98,10 +93,44 @@ public abstract class AbstractQueryDevice extends Statement 
{
     return tableName;
   }
 
+  public QualifiedName getName() {
+    return name;
+  }
+
   public Expression getRawExpression() {
     return rawExpression;
   }
 
+  public void setRawExpression(final Expression rawExpression) {
+    this.rawExpression = rawExpression;
+  }
+
+  public boolean parseRawExpression(
+      final List<DeviceEntry> entries,
+      final TsTable tableInstance,
+      final List<String> attributeColumns,
+      final MPPQueryContext context) {
+    if (Objects.isNull(rawExpression)) {
+      return true;
+    }
+    rawExpression =
+        
ExtractCommonPredicatesExpressionRewriter.extractCommonPredicates(rawExpression);
+    return TableDeviceSchemaFetcher.getInstance()
+        .parseFilter4TraverseDevice(
+            database,
+            tableInstance,
+            (rawExpression instanceof LogicalExpression
+                    && ((LogicalExpression) rawExpression).getOperator()
+                        == LogicalExpression.Operator.AND)
+                ? ((LogicalExpression) rawExpression).getTerms()
+                : Collections.singletonList(rawExpression),
+            this,
+            entries,
+            attributeColumns,
+            context,
+            true);
+  }
+
   public List<List<SchemaFilter>> getIdDeterminedFilterList() {
     if (idDeterminedFilterList == null) {
       idDeterminedFilterList = 
Collections.singletonList(Collections.emptyList());
@@ -109,10 +138,18 @@ public abstract class AbstractQueryDevice extends 
Statement {
     return idDeterminedFilterList;
   }
 
+  public void setIdDeterminedFilterList(final List<List<SchemaFilter>> 
idDeterminedFilterList) {
+    this.idDeterminedFilterList = idDeterminedFilterList;
+  }
+
   public Expression getIdFuzzyPredicate() {
     return idFuzzyPredicate;
   }
 
+  public void setIdFuzzyPredicate(final Expression idFuzzyPredicate) {
+    this.idFuzzyPredicate = idFuzzyPredicate;
+  }
+
   public boolean isIdDetermined() {
     return Objects.nonNull(partitionKeyList);
   }
@@ -121,6 +158,10 @@ public abstract class AbstractQueryDevice extends 
Statement {
     return partitionKeyList;
   }
 
+  public void setPartitionKeyList(final List<IDeviceID> partitionKeyList) {
+    this.partitionKeyList = partitionKeyList;
+  }
+
   @Override
   public List<? extends Node> getChildren() {
     return null;
@@ -130,7 +171,7 @@ public abstract class AbstractQueryDevice extends Statement 
{
   public boolean equals(final Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
-    final AbstractQueryDevice that = (AbstractQueryDevice) o;
+    final AbstractTraverseDevice that = (AbstractTraverseDevice) o;
     return Objects.equals(database, that.database)
         && Objects.equals(tableName, that.tableName)
         && Objects.equals(rawExpression, that.rawExpression)
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDevice.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDevice.java
index d7813b131de..3b890d24896 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDevice.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDevice.java
@@ -19,13 +19,41 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
 
-public class CountDevice extends AbstractQueryDevice {
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.TsBlockBuilder;
+
+import java.util.Collections;
+
+public class CountDevice extends AbstractQueryDeviceWithCache {
+
+  public static final String COUNT_DEVICE_HEADER_STRING = "count(devices)";
 
   // For sql-input show device usage
   public CountDevice(final QualifiedName name, final Expression rawExpression) 
{
     super(name, rawExpression);
   }
 
+  @Override
+  public DatasetHeader getDataSetHeader() {
+    return new DatasetHeader(
+        Collections.singletonList(new ColumnHeader(COUNT_DEVICE_HEADER_STRING, 
TSDataType.INT64)),
+        true);
+  }
+
+  @Override
+  public TsBlock getTsBlock() {
+    final TsBlockBuilder tsBlockBuilder =
+        new TsBlockBuilder(Collections.singletonList(TSDataType.INT64));
+    tsBlockBuilder.getTimeColumnBuilder().writeLong(0L);
+    tsBlockBuilder.getColumnBuilder(0).writeLong(results.size());
+    tsBlockBuilder.declarePosition();
+    return tsBlockBuilder.build();
+  }
+
   @Override
   public <R, C> R accept(final AstVisitor<R, C> visitor, final C context) {
     return visitor.visitCountDevice(this, context);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowDevice.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowDevice.java
index ca7cf135b86..cba444f6b51 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowDevice.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowDevice.java
@@ -19,27 +19,42 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
 
-import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+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.operator.schema.source.TableDeviceQuerySource;
 
-import org.apache.tsfile.file.metadata.IDeviceID;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.TsBlockBuilder;
 
-import java.util.List;
+import java.util.stream.Collectors;
 
-public class ShowDevice extends AbstractQueryDevice {
+public class ShowDevice extends AbstractQueryDeviceWithCache {
 
-  // For sql-input show device usage
   public ShowDevice(final QualifiedName name, final Expression rawExpression) {
     super(name, rawExpression);
   }
 
-  // For device fetch serving data query
-  public ShowDevice(
-      final String database,
-      final String tableName,
-      final List<List<SchemaFilter>> idDeterminedPredicateList,
-      final Expression idFuzzyFilterList,
-      final List<IDeviceID> partitionKeyList) {
-    super(database, tableName, idDeterminedPredicateList, idFuzzyFilterList, 
partitionKeyList);
+  public ShowDevice(final String database, final String tableName) {
+    super(database, tableName);
+  }
+
+  @Override
+  public DatasetHeader getDataSetHeader() {
+    return new DatasetHeader(columnHeaderList, true);
+  }
+
+  @Override
+  public TsBlock getTsBlock() {
+    final TsBlockBuilder tsBlockBuilder =
+        new TsBlockBuilder(
+            columnHeaderList.stream()
+                .map(ColumnHeader::getColumnType)
+                .collect(Collectors.toList()));
+    results.forEach(
+        result ->
+            TableDeviceQuerySource.transformToTsBlockColumns(
+                result, tsBlockBuilder, database, tableName, columnHeaderList, 
1));
+    return tsBlockBuilder.build();
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index 391d5cd0ff2..7926c9226ea 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -535,20 +535,18 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
 
   @Override
   public Node visitShowDevicesStatement(final 
RelationalSqlParser.ShowDevicesStatementContext ctx) {
-    if (ctx.WHERE() != null || ctx.LIMIT() != null || ctx.OFFSET() != null) {
-      throw new UnsupportedOperationException(
-          "Show devices with WHERE/LIMIT/OFFSET is unsupported yet.");
+    if (ctx.LIMIT() != null || ctx.OFFSET() != null) {
+      throw new UnsupportedOperationException("Show devices with LIMIT/OFFSET 
is unsupported yet.");
     }
-    return new ShowDevice(getQualifiedName(ctx.tableName), null);
+    return new ShowDevice(
+        getQualifiedName(ctx.tableName), visitIfPresent(ctx.where, 
Expression.class).orElse(null));
   }
 
   @Override
   public Node visitCountDevicesStatement(
       final RelationalSqlParser.CountDevicesStatementContext ctx) {
-    if (ctx.WHERE() != null) {
-      throw new UnsupportedOperationException("Count devices with WHERE is 
unsupported yet.");
-    }
-    return new CountDevice(getQualifiedName(ctx.tableName), null);
+    return new CountDevice(
+        getQualifiedName(ctx.tableName), visitIfPresent(ctx.where, 
Expression.class).orElse(null));
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java
index 2f0f805ea45..b24da4adb5a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java
@@ -32,7 +32,6 @@ import 
org.apache.iotdb.db.schemaengine.rescon.ISchemaRegionStatistics;
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowDevicesPlan;
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowNodesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowTimeSeriesPlan;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl.ShowTableDevicesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.INodeSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
@@ -339,8 +338,8 @@ public interface ISchemaRegion {
   ISchemaReader<INodeSchemaInfo> getNodeReader(IShowNodesPlan showNodesPlan)
       throws MetadataException;
 
-  ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
-      final ShowTableDevicesPlan showTableDevicesPlan) throws 
MetadataException;
+  ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(final PartialPath 
pathPattern)
+      throws MetadataException;
 
   ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
       final String table, final List<Object[]> devicePathList) throws 
MetadataException;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java
index 22fbeaae2a7..14b21fcac6a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java
@@ -62,7 +62,6 @@ import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.IMemMN
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowDevicesPlan;
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowNodesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowTimeSeriesPlan;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl.ShowTableDevicesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.INodeSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
@@ -1402,12 +1401,10 @@ public class SchemaRegionMemoryImpl implements 
ISchemaRegion {
   }
 
   @Override
-  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
-      final ShowTableDevicesPlan showTableDevicesPlan) throws 
MetadataException {
+  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(final 
PartialPath pathPattern)
+      throws MetadataException {
     return mtree.getTableDeviceReader(
-        showTableDevicesPlan.getDevicePattern(),
-        showTableDevicesPlan.getDeviceFilter(),
-        (pointer, name) -> deviceAttributeStore.getAttribute(pointer, name));
+        pathPattern, (pointer, name) -> 
deviceAttributeStore.getAttribute(pointer, name));
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
index b790545b5d6..1baecf38a32 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
@@ -63,7 +63,6 @@ import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.pbtree.mnode.ICa
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowDevicesPlan;
 import org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowNodesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.IShowTimeSeriesPlan;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl.ShowTableDevicesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.INodeSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
@@ -1477,8 +1476,8 @@ public class SchemaRegionPBTreeImpl implements 
ISchemaRegion {
   }
 
   @Override
-  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
-      ShowTableDevicesPlan showTableDevicesPlan) throws MetadataException {
+  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(final 
PartialPath pathPattern)
+      throws MetadataException {
     throw new UnsupportedOperationException();
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
index 04b8d9ac003..123002cb588 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
@@ -21,12 +21,10 @@ package 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.MetadataException;
-import org.apache.iotdb.commons.path.ExtendedPartialPath;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.commons.schema.SchemaConstant;
-import org.apache.iotdb.commons.schema.filter.SchemaFilter;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
 import org.apache.iotdb.commons.schema.node.utils.IMNodeFactory;
@@ -1101,9 +1099,7 @@ public class MTreeBelowSGMemoryImpl {
 
   // Used for device query/fetch with filters during show device or table query
   public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
-      final PartialPath pattern,
-      final SchemaFilter deviceFilter,
-      final BiFunction<Integer, String, String> attributeProvider)
+      final PartialPath pattern, final BiFunction<Integer, String, String> 
attributeProvider)
       throws MetadataException {
 
     final EntityCollector<IDeviceSchemaInfo, IMemMNode> collector =
@@ -1127,9 +1123,6 @@ public class MTreeBelowSGMemoryImpl {
         };
     return new ISchemaReader<IDeviceSchemaInfo>() {
 
-      private final DeviceFilterVisitor filterVisitor = new 
DeviceFilterVisitor();
-      private IDeviceSchemaInfo next;
-
       public boolean isSuccess() {
         return collector.isSuccess();
       }
@@ -1147,33 +1140,15 @@ public class MTreeBelowSGMemoryImpl {
       }
 
       public boolean hasNext() {
-        while (next == null && collector.hasNext()) {
-          final IDeviceSchemaInfo temp = collector.next();
-          if (deviceFilter == null || filterVisitor.process(deviceFilter, 
temp)) {
-            next = temp;
-          }
-        }
-        return next != null;
+        return collector.hasNext();
       }
 
       public IDeviceSchemaInfo next() {
-        if (!hasNext()) {
-          throw new NoSuchElementException();
-        }
-        final IDeviceSchemaInfo result = next;
-        next = null;
-        return result;
+        return collector.next();
       }
     };
   }
 
-  private int computeSmallestNullableIndex(final PartialPath partialPath) {
-    if (!(partialPath instanceof ExtendedPartialPath)) {
-      return partialPath.getNodeLength() - 1;
-    }
-    return 0;
-  }
-
   // used for device fetch with explicit device id/path during table insertion
   public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
       final String table,
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/impl/ShowDevicesResult.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/impl/ShowDevicesResult.java
index 767bc4c7935..28a5ea85fd7 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/impl/ShowDevicesResult.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/impl/ShowDevicesResult.java
@@ -16,11 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.impl;
 
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.UnaryOperator;
@@ -73,6 +78,19 @@ public class ShowDevicesResult extends ShowSchemaResult 
implements IDeviceSchema
     return rawNodes == null ? super.getPartialPath() : new 
PartialPath(rawNodes);
   }
 
+  public static ShowDevicesResult convertDeviceEntry2ShowDeviceResult(
+      final DeviceEntry entry, final List<String> attributeColumns) {
+    final ShowDevicesResult result =
+        new ShowDevicesResult(
+            entry.getDeviceID().toString(), null, -1, (String[]) 
entry.getDeviceID().getSegments());
+    final Map<String, String> attributeProviderMap = new HashMap<>();
+    for (int i = 0; i < attributeColumns.size(); ++i) {
+      attributeProviderMap.put(attributeColumns.get(i), 
entry.getAttributeColumnValues().get(i));
+    }
+    result.setAttributeProvider(attributeProviderMap::get);
+    return result;
+  }
+
   @Override
   public String toString() {
     return "ShowDevicesResult{"
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTableDeviceTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTableDeviceTest.java
index 82c5c953735..07b52d5b5c0 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTableDeviceTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTableDeviceTest.java
@@ -19,8 +19,6 @@
 
 package org.apache.iotdb.db.metadata.schemaRegion;
 
-import org.apache.iotdb.commons.schema.filter.impl.multichildren.OrFilter;
-import org.apache.iotdb.commons.schema.filter.impl.singlechild.AttributeFilter;
 import org.apache.iotdb.commons.schema.filter.impl.singlechild.IdFilter;
 import org.apache.iotdb.commons.schema.filter.impl.singlechild.NotFilter;
 import org.apache.iotdb.commons.schema.filter.impl.values.InFilter;
@@ -144,8 +142,7 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             3,
             Arrays.asList(
                 new IdFilter(new PreciseFilter("hebei"), 0),
-                new IdFilter(new PreciseFilter("p_1"), 1)),
-            null);
+                new IdFilter(new PreciseFilter("p_1"), 1)));
     Assert.assertEquals(2, deviceSchemaInfoList.size());
 
     deviceSchemaInfoList =
@@ -153,8 +150,7 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             schemaRegion,
             tableName,
             3,
-            Collections.singletonList(new IdFilter(new PreciseFilter("p_1"), 
1)),
-            null);
+            Collections.singletonList(new IdFilter(new PreciseFilter("p_1"), 
1)));
     Assert.assertEquals(3, deviceSchemaInfoList.size());
 
     deviceSchemaInfoList =
@@ -162,31 +158,9 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             schemaRegion,
             tableName,
             3,
-            Collections.singletonList(new IdFilter(new PreciseFilter("p_1"), 
1)),
-            new AttributeFilter(new PreciseFilter("daily"), "cycle"));
-    Assert.assertEquals(1, deviceSchemaInfoList.size());
-
-    deviceSchemaInfoList =
-        SchemaRegionTestUtil.getTableDevice(
-            schemaRegion,
-            tableName,
-            3,
-            Collections.emptyList(),
-            new OrFilter(
-                Arrays.asList(
-                    new IdFilter(new PreciseFilter("p_1"), 1),
-                    new AttributeFilter(new PreciseFilter("daily"), 
"cycle"))));
-    Assert.assertEquals(3, deviceSchemaInfoList.size());
-
-    deviceSchemaInfoList =
-        SchemaRegionTestUtil.getTableDevice(
-            schemaRegion,
-            tableName,
-            3,
-            Collections.singletonList(new IdFilter(new 
InFilter(Collections.singleton("d_1")), 2)),
-            new AttributeFilter(new 
LikeFilter(parseLikePatternToRegex("_____")), "cycle"));
+            Collections.singletonList(new IdFilter(new 
InFilter(Collections.singleton("d_1")), 2)));
 
-    Assert.assertEquals(1, deviceSchemaInfoList.size());
+    Assert.assertEquals(2, deviceSchemaInfoList.size());
 
     // Test multi filters on one id
     deviceSchemaInfoList =
@@ -196,8 +170,7 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             3,
             Arrays.asList(
                 new IdFilter(new InFilter(new HashSet<>(Arrays.asList("d_0", 
"d_1"))), 2),
-                new IdFilter(new LikeFilter(parseLikePatternToRegex("__1")), 
2)),
-            null);
+                new IdFilter(new LikeFilter(parseLikePatternToRegex("__1")), 
2)));
 
     Assert.assertEquals(2, deviceSchemaInfoList.size());
   }
@@ -247,8 +220,7 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             schemaRegion,
             tableName,
             3,
-            Collections.singletonList(new IdFilter(new PreciseFilter((String) 
null), 0)),
-            null);
+            Collections.singletonList(new IdFilter(new PreciseFilter((String) 
null), 0)));
     Assert.assertEquals(1, deviceSchemaInfoList.size());
 
     deviceSchemaInfoList =
@@ -256,30 +228,16 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             schemaRegion,
             tableName,
             3,
-            Collections.singletonList(new IdFilter(new PreciseFilter((String) 
null), 1)),
-            null);
+            Collections.singletonList(new IdFilter(new PreciseFilter((String) 
null), 1)));
     Assert.assertEquals(2, deviceSchemaInfoList.size());
 
-    deviceSchemaInfoList =
-        SchemaRegionTestUtil.getTableDevice(
-            schemaRegion,
-            tableName,
-            3,
-            Collections.emptyList(),
-            new OrFilter(
-                Arrays.asList(
-                    new IdFilter(new PreciseFilter((String) null), 2),
-                    new AttributeFilter(new PreciseFilter((String) null), 
"cycle"))));
-    Assert.assertEquals(4, deviceSchemaInfoList.size());
-
     deviceSchemaInfoList =
         SchemaRegionTestUtil.getTableDevice(
             schemaRegion,
             tableName,
             3,
             Collections.singletonList(
-                new IdFilter(new NotFilter(new PreciseFilter((String) null)), 
2)),
-            null);
+                new IdFilter(new NotFilter(new PreciseFilter((String) null)), 
2)));
 
     Assert.assertEquals(2, deviceSchemaInfoList.size());
 
@@ -289,8 +247,7 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             tableName,
             3,
             Collections.singletonList(
-                new IdFilter(new LikeFilter(parseLikePatternToRegex("%")), 2)),
-            null);
+                new IdFilter(new LikeFilter(parseLikePatternToRegex("%")), 
2)));
 
     Assert.assertEquals(2, deviceSchemaInfoList.size());
   }
@@ -336,19 +293,8 @@ public class SchemaRegionTableDeviceTest extends 
AbstractSchemaRegionTest {
             schemaRegion,
             tableName,
             4,
-            Collections.singletonList(new IdFilter(new PreciseFilter("r_1"), 
3)),
-            null);
+            Collections.singletonList(new IdFilter(new PreciseFilter("r_1"), 
3)));
     Assert.assertEquals(1, deviceSchemaInfoList.size());
-
-    // todo implement device query after table column extension
-    //    deviceSchemaInfoList =
-    //            SchemaRegionTestUtil.getTableDevice(
-    //                    schemaRegion,
-    //                    tableName,
-    //                    4,
-    //                    Collections.singletonList(new DeviceIdFilter(3, 
null)),
-    //                    null);
-    //    Assert.assertEquals(2, deviceSchemaInfoList.size());
   }
 
   @Test
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTestUtil.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTestUtil.java
index d1480cf344e..d431073f070 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTestUtil.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTestUtil.java
@@ -28,7 +28,6 @@ import 
org.apache.iotdb.commons.schema.filter.SchemaFilterFactory;
 import org.apache.iotdb.commons.schema.filter.impl.DeviceFilterUtil;
 import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.SchemaRegionReadPlanFactory;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl.ShowTableDevicesPlan;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.INodeSchemaInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
@@ -449,8 +448,7 @@ public class SchemaRegionTestUtil {
       final ISchemaRegion schemaRegion,
       final String table,
       final int idColumnNum,
-      final List<SchemaFilter> idDeterminedFilterList,
-      final SchemaFilter idFuzzyFilter) {
+      final List<SchemaFilter> idDeterminedFilterList) {
     final List<PartialPath> patternList =
         DeviceFilterUtil.convertToDevicePattern(
             schemaRegion.getDatabaseFullPath().substring(ROOT.length() + 1),
@@ -460,7 +458,7 @@ public class SchemaRegionTestUtil {
     final List<IDeviceSchemaInfo> result = new ArrayList<>();
     for (final PartialPath pattern : patternList) {
       try (final ISchemaReader<IDeviceSchemaInfo> reader =
-          schemaRegion.getTableDeviceReader(new ShowTableDevicesPlan(pattern, 
idFuzzyFilter))) {
+          schemaRegion.getTableDeviceReader(pattern)) {
         while (reader.hasNext()) {
           result.add(reader.next());
         }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
index f7ca7932cfe..f4360e5f807 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
@@ -74,7 +74,7 @@ public class TsTable {
 
   private transient int idNums = 0;
 
-  public TsTable(String tableName) {
+  public TsTable(final String tableName) {
     this.tableName = tableName;
     columnSchemaMap.put(TIME_COLUMN_NAME, TIME_COLUMN_SCHEMA);
   }
@@ -83,7 +83,7 @@ public class TsTable {
     return tableName;
   }
 
-  public TsTableColumnSchema getColumnSchema(String columnName) {
+  public TsTableColumnSchema getColumnSchema(final String columnName) {
     readWriteLock.readLock().lock();
     try {
       return columnSchemaMap.get(columnName);
@@ -92,7 +92,7 @@ public class TsTable {
     }
   }
 
-  public void addColumnSchema(TsTableColumnSchema columnSchema) {
+  public void addColumnSchema(final TsTableColumnSchema columnSchema) {
     readWriteLock.writeLock().lock();
     try {
       columnSchemaMap.put(columnSchema.getColumnName(), columnSchema);

Reply via email to