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

zyk pushed a commit to branch table-model-debug
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 34e5b0e5ac3a7a69906d50f7a6f9e4e62ea69d34
Author: MarcosZyk <[email protected]>
AuthorDate: Sun Apr 21 21:18:23 2024 +0800

    implement schema filter
---
 .../iotdb/confignode/conf/ConfigNodeConfig.java    |   2 +-
 .../schema/source/SchemaSourceFactory.java         |  11 +
 .../schema/source/TableDeviceSchemaSource.java     | 226 +++++++++++++++++++++
 .../queryengine/plan/analyze/AnalyzeVisitor.java   |  70 +++++++
 .../plan/planner/LogicalPlanBuilder.java           |  20 ++
 .../plan/planner/LogicalPlanVisitor.java           |  40 ++++
 .../plan/planner/OperatorTreeGenerator.java        |  22 ++
 .../planner/distribution/ExchangeNodeAdder.java    |   6 +
 .../plan/planner/plan/node/PlanVisitor.java        |   5 +
 .../node/metedata/read/TableDeviceScanNode.java    | 141 +++++++++++++
 .../analyzer/schema/TableModelSchemaFetcher.java   | 212 ++++++++++++++++++-
 .../plan/relational/metadata/DeviceEntry.java      |  10 +
 .../relational/metadata/TableMetadataImpl.java     |  18 +-
 .../planner/optimizations/IndexScan.java           |   3 +
 .../plan/statement/StatementVisitor.java           |   5 +
 .../metadata/ShowTableDevicesStatement.java        |  69 +++++++
 .../schemaengine/schemaregion/ISchemaRegion.java   |   3 +
 .../attribute/DeviceAttributeStore.java            |   7 +-
 .../attribute/IDeviceAttributeStore.java           |   2 +
 .../schemaregion/impl/SchemaRegionMemoryImpl.java  |  13 +-
 .../schemaregion/impl/SchemaRegionPBTreeImpl.java  |   7 +
 .../mtree/impl/mem/MTreeBelowSGMemoryImpl.java     |  82 +++++++-
 .../read/req/impl/ShowTableDevicesPlan.java        |  40 ++++
 .../read/resp/info/IDeviceSchemaInfo.java          |   2 +
 .../read/resp/info/impl/ShowDevicesResult.java     |  12 ++
 .../utils/filter/DeviceFilterVisitor.java          |  12 ++
 .../commons/schema/filter/SchemaFilterType.java    |  11 +
 .../commons/schema/filter/SchemaFilterVisitor.java |  15 ++
 .../schema/filter/impl/DeviceAttributeFilter.java  |  63 ++++++
 .../commons/schema/filter/impl/DeviceIdFilter.java |  63 ++++++
 .../iotdb/commons/schema/filter/impl/OrFilter.java |  74 +++++++
 .../iotdb/db/relational/sql/parser/AstBuilder.java |   4 +-
 .../iotdb/db/relational/sql/tree/ShowDevice.java   |  67 ++++++
 33 files changed, 1317 insertions(+), 20 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
index 3875bf09080..3177bf0c0fd 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
@@ -101,7 +101,7 @@ public class ConfigNodeConfig {
    * DataRegionGroups for each Database. When set 
data_region_group_extension_policy=AUTO, this
    * parameter is the default minimal number of DataRegionGroups for each 
Database.
    */
-  private int defaultDataRegionGroupNumPerDatabase = 2;
+  private int defaultDataRegionGroupNumPerDatabase = 1;
 
   /** The maximum number of DataRegions expected to be managed by each 
DataNode. */
   private double dataRegionPerDataNode = 5.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 7fe10842579..9e3028b62f0 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
@@ -22,6 +22,7 @@ package 
org.apache.iotdb.db.queryengine.execution.operator.schema.source;
 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.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;
@@ -98,4 +99,14 @@ public class SchemaSourceFactory {
       PathPatternTree scope) {
     return new LogicalViewSchemaSource(pathPattern, limit, offset, 
schemaFilter, scope);
   }
+
+  public static ISchemaSource<IDeviceSchemaInfo> getTableDeviceSchemaSource(
+      String database,
+      String tableName,
+      List<SchemaFilter> idDeterminedFilterList,
+      List<SchemaFilter> idFuzzyFilterList,
+      List<ColumnHeader> columnHeaderList) {
+    return new TableDeviceSchemaSource(
+        database, tableName, idDeterminedFilterList, idFuzzyFilterList, 
columnHeaderList);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceSchemaSource.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceSchemaSource.java
new file mode 100644
index 00000000000..52999761142
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceSchemaSource.java
@@ -0,0 +1,226 @@
+package org.apache.iotdb.db.queryengine.execution.operator.schema.source;
+
+import org.apache.iotdb.commons.exception.runtime.SchemaExecutionException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceIdFilter;
+import org.apache.iotdb.commons.schema.filter.impl.OrFilter;
+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.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.read.common.block.TsBlockBuilder;
+import org.apache.tsfile.utils.Binary;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_ROOT;
+
+public class TableDeviceSchemaSource implements 
ISchemaSource<IDeviceSchemaInfo> {
+
+  private String database;
+
+  private String tableName;
+
+  private List<SchemaFilter> idDeterminedFilterList;
+
+  private List<SchemaFilter> idFuzzyFilterList;
+
+  private List<ColumnHeader> columnHeaderList;
+
+  public TableDeviceSchemaSource(
+      String database,
+      String tableName,
+      List<SchemaFilter> idDeterminedFilterList,
+      List<SchemaFilter> idFuzzyFilterList,
+      List<ColumnHeader> columnHeaderList) {
+    this.database = database;
+    this.tableName = tableName;
+    this.idDeterminedFilterList = idDeterminedFilterList;
+    this.idFuzzyFilterList = idFuzzyFilterList;
+    this.columnHeaderList = columnHeaderList;
+  }
+
+  @Override
+  public ISchemaReader<IDeviceSchemaInfo> getSchemaReader(ISchemaRegion 
schemaRegion) {
+    List<PartialPath> devicePatternList = getDevicePatternList();
+    return new ISchemaReader<IDeviceSchemaInfo>() {
+
+      private ISchemaReader<IDeviceSchemaInfo> deviceReader;
+      private Throwable throwable;
+      private int index = 0;
+
+      @Override
+      public boolean isSuccess() {
+        return throwable == null && (deviceReader == null || 
deviceReader.isSuccess());
+      }
+
+      @Override
+      public Throwable getFailure() {
+        if (throwable != null) {
+          return throwable;
+        } else if (deviceReader != null) {
+          return deviceReader.getFailure();
+        }
+        return null;
+      }
+
+      @Override
+      public ListenableFuture<?> isBlocked() {
+        return NOT_BLOCKED;
+      }
+
+      @Override
+      public boolean hasNext() {
+        try {
+          if (throwable != null) {
+            return false;
+          }
+          if (deviceReader != null) {
+            if (deviceReader.hasNext()) {
+              return true;
+            } else {
+              deviceReader.close();
+              if (!deviceReader.isSuccess()) {
+                throwable = deviceReader.getFailure();
+                return false;
+              }
+            }
+          }
+
+          while (index < devicePatternList.size()) {
+            deviceReader =
+                schemaRegion.getTableDeviceReader(
+                    new ShowTableDevicesPlan(devicePatternList.get(index), 
idFuzzyFilterList));
+            index++;
+            if (deviceReader.hasNext()) {
+              return true;
+            } else {
+              deviceReader.close();
+            }
+          }
+          return false;
+        } catch (Exception e) {
+          throw new SchemaExecutionException(e.getMessage(), e);
+        }
+      }
+
+      @Override
+      public IDeviceSchemaInfo next() {
+        if (!hasNext()) {
+          throw new NoSuchElementException();
+        }
+        return deviceReader.next();
+      }
+
+      @Override
+      public void close() throws Exception {
+        if (deviceReader != null) {
+          deviceReader.close();
+        }
+      }
+    };
+  }
+
+  private List<PartialPath> getDevicePatternList() {
+    int length = DataNodeTableCache.getInstance().getTable(database, 
tableName).getIdNums() + 3;
+    String[] nodes = new String[length];
+    Arrays.fill(nodes, "*");
+    nodes[0] = PATH_ROOT;
+    nodes[1] = database;
+    nodes[2] = tableName;
+    Map<Integer, List<String>> orValueMap = new HashMap<>();
+    for (SchemaFilter schemaFilter : idDeterminedFilterList) {
+      if 
(schemaFilter.getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)) {
+        DeviceIdFilter deviceIdFilter = (DeviceIdFilter) schemaFilter;
+        nodes[deviceIdFilter.getIndex() + 3] = deviceIdFilter.getValue();
+      } else if 
(schemaFilter.getSchemaFilterType().equals(SchemaFilterType.OR)) {
+        OrFilter orFilter = (OrFilter) schemaFilter;
+        if 
(orFilter.getLeft().getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)
+            && 
orFilter.getRight().getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)) {
+          DeviceIdFilter deviceIdFilter = (DeviceIdFilter) orFilter.getLeft();
+          nodes[deviceIdFilter.getIndex() + 3] = deviceIdFilter.getValue();
+          deviceIdFilter = (DeviceIdFilter) orFilter.getLeft();
+          orValueMap
+              .computeIfAbsent(deviceIdFilter.getIndex(), k -> new 
ArrayList<>())
+              .add(deviceIdFilter.getValue());
+        }
+      }
+    }
+
+    PartialPath path = new PartialPath(nodes);
+    List<PartialPath> pathList = new ArrayList<>();
+    pathList.add(path);
+    for (Map.Entry<Integer, List<String>> entry : orValueMap.entrySet()) {
+      for (int i = 0, size = pathList.size(); i < size; i++) {
+        for (String value : entry.getValue()) {
+          nodes = Arrays.copyOf(pathList.get(i).getNodes(), length);
+          nodes[entry.getKey() + 3] = value;
+          path = new PartialPath(nodes);
+          pathList.add(path);
+        }
+      }
+    }
+
+    return pathList;
+  }
+
+  @Override
+  public List<ColumnHeader> getInfoQueryColumnHeaders() {
+    return columnHeaderList;
+  }
+
+  @Override
+  public void transformToTsBlockColumns(
+      IDeviceSchemaInfo schemaInfo, TsBlockBuilder builder, String database) {
+    builder.getTimeColumnBuilder().writeLong(0L);
+    int resultIndex = 0;
+    int idIndex = 0;
+    PartialPath devicePath = schemaInfo.getPartialPath();
+    TsTable table = DataNodeTableCache.getInstance().getTable(this.database, 
tableName);
+    TsTableColumnSchema columnSchema;
+    for (ColumnHeader columnHeader : columnHeaderList) {
+      columnSchema = table.getColumnSchema(columnHeader.getColumnName());
+      if (columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)) {
+        builder
+            .getColumnBuilder(resultIndex)
+            .writeBinary(
+                new Binary(devicePath.getNodes()[idIndex + 3], 
TSFileConfig.STRING_CHARSET));
+        idIndex++;
+      } else if 
(columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE)) {
+        builder
+            .getColumnBuilder(resultIndex)
+            .writeBinary(
+                new Binary(
+                    schemaInfo.getAttributeValue(columnHeader.getColumnName()),
+                    TSFileConfig.STRING_CHARSET));
+      }
+      resultIndex++;
+    }
+    builder.declarePosition();
+  }
+
+  @Override
+  public boolean hasSchemaStatistic(ISchemaRegion schemaRegion) {
+    return false;
+  }
+
+  @Override
+  public long getSchemaStatistic(ISchemaRegion schemaRegion) {
+    return 0;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index f60893d2cd7..bd94bf2b0fd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -33,6 +33,11 @@ import org.apache.iotdb.commons.partition.SchemaPartition;
 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.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceIdFilter;
+import org.apache.iotdb.commons.schema.filter.impl.OrFilter;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
 import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
 import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
@@ -127,6 +132,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowCurrentTimest
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTableDevicesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.BatchActivateTemplateStatement;
@@ -180,6 +186,7 @@ import static 
org.apache.iotdb.commons.conf.IoTDBConstant.ALLOWED_SCHEMA_PROPS;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.DEADBAND;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.LOSS;
 import static 
org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_ROOT;
 import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_MATCH_PATTERN;
 import static 
org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.DEVICE;
 import static 
org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME;
@@ -3700,4 +3707,67 @@ public class AnalyzeVisitor extends 
StatementVisitor<Analysis, MPPQueryContext>
 
     return analysis;
   }
+
+  @Override
+  public Analysis visitShowTableDevices(
+      ShowTableDevicesStatement statement, MPPQueryContext context) {
+    context.setQueryType(QueryType.READ);
+    Analysis analysis = new Analysis();
+    analysis.setStatement(statement);
+
+    String database = statement.getDatabase();
+    String tableName = statement.getTableName();
+    List<TsTableColumnSchema> columnSchemaList =
+        DataNodeTableCache.getInstance().getTable(database, 
tableName).getColumnList();
+
+    int length = DataNodeTableCache.getInstance().getTable(database, 
tableName).getIdNums() + 3 + 1;
+    String[] nodes = new String[length];
+    Arrays.fill(nodes, "*");
+    nodes[0] = PATH_ROOT;
+    nodes[1] = database;
+    nodes[2] = tableName;
+    nodes[nodes.length - 1] = ONE_LEVEL_PATH_WILDCARD;
+    Map<Integer, List<String>> orValueMap = new HashMap<>();
+    for (SchemaFilter schemaFilter : statement.getIdDeterminedFilterList()) {
+      if 
(schemaFilter.getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)) {
+        DeviceIdFilter deviceIdFilter = (DeviceIdFilter) schemaFilter;
+        nodes[deviceIdFilter.getIndex() + 3] = deviceIdFilter.getValue();
+      } else if 
(schemaFilter.getSchemaFilterType().equals(SchemaFilterType.OR)) {
+        OrFilter orFilter = (OrFilter) schemaFilter;
+        if 
(orFilter.getLeft().getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)
+            && 
orFilter.getRight().getSchemaFilterType().equals(SchemaFilterType.DEVICE_ID)) {
+          DeviceIdFilter deviceIdFilter = (DeviceIdFilter) orFilter.getLeft();
+          nodes[deviceIdFilter.getIndex() + 3] = deviceIdFilter.getValue();
+          deviceIdFilter = (DeviceIdFilter) orFilter.getLeft();
+          orValueMap
+              .computeIfAbsent(deviceIdFilter.getIndex(), k -> new 
ArrayList<>())
+              .add(deviceIdFilter.getValue());
+        }
+      }
+    }
+    PathPatternTree patternTree = new PathPatternTree();
+    PartialPath path = new PartialPath(nodes);
+    patternTree.appendFullPath(path);
+    List<PartialPath> pathList = new ArrayList<>();
+    pathList.add(path);
+    for (Map.Entry<Integer, List<String>> entry : orValueMap.entrySet()) {
+      for (int i = 0, size = pathList.size(); i < size; i++) {
+        for (String value : entry.getValue()) {
+          nodes = Arrays.copyOf(pathList.get(i).getNodes(), length);
+          nodes[entry.getKey() + 3] = value;
+          path = new PartialPath(nodes);
+          pathList.add(path);
+          patternTree.appendFullPath(path);
+        }
+      }
+    }
+
+    SchemaPartition partition =
+        partitionFetcher.getOrCreateSchemaPartition(
+            patternTree, context.getSession().getUserName());
+
+    analysis.setSchemaPartitionInfo(partition);
+
+    return analysis;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
index 2a56d0e8140..1d31828c51b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
@@ -30,6 +30,7 @@ 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.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
 import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
 import 
org.apache.iotdb.db.queryengine.execution.aggregation.AccumulatorFactory;
 import org.apache.iotdb.db.queryengine.execution.operator.AggregationUtil;
@@ -54,6 +55,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.Sche
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TableDeviceScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationNode;
@@ -1642,4 +1644,22 @@ public class LogicalPlanBuilder {
             new SlidingTimeColumnGeneratorParameter(groupByTimeParameter, 
ascending));
     return this;
   }
+
+  public LogicalPlanBuilder planTableDeviceSource(
+      String database,
+      String tableName,
+      List<SchemaFilter> idDeterminedFilterList,
+      List<SchemaFilter> idFuzzyFilterList,
+      List<ColumnHeader> columnHeaderList) {
+    this.root =
+        new TableDeviceScanNode(
+            context.getQueryId().genPlanNodeId(),
+            database,
+            tableName,
+            idDeterminedFilterList,
+            idFuzzyFilterList,
+            columnHeaderList,
+            null);
+    return this;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
index ffd75a5b42c..d61ba35b164 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
@@ -21,10 +21,14 @@ package org.apache.iotdb.db.queryengine.plan.planner;
 import org.apache.iotdb.commons.path.AlignedPath;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
 import org.apache.iotdb.commons.udf.builtin.BuiltinAggregationFunction;
 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.ColumnHeaderConstant;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
 import org.apache.iotdb.db.queryengine.plan.analyze.Analysis;
 import org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer;
 import org.apache.iotdb.db.queryengine.plan.expression.Expression;
@@ -84,6 +88,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesS
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTableDevicesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.BatchActivateTemplateStatement;
@@ -93,6 +98,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.view.ShowLogicalV
 import 
org.apache.iotdb.db.queryengine.plan.statement.pipe.PipeEnrichedStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainAnalyzeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowQueriesStatement;
+import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 import org.apache.iotdb.db.schemaengine.template.Template;
 
 import org.apache.commons.lang3.StringUtils;
@@ -1022,4 +1028,38 @@ public class LogicalPlanVisitor extends 
StatementVisitor<PlanNode, MPPQueryConte
         createTableDeviceStatement.getAttributeNameList(),
         createTableDeviceStatement.getAttributeValueList());
   }
+
+  @Override
+  public PlanNode visitShowTableDevices(
+      ShowTableDevicesStatement statement, MPPQueryContext context) {
+    LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(analysis, context);
+
+    List<TsTableColumnSchema> columnSchemaList =
+        DataNodeTableCache.getInstance()
+            .getTable(statement.getDatabase(), statement.getTableName())
+            .getColumnList();
+
+    List<ColumnHeader> columnHeaderList = new 
ArrayList<>(columnSchemaList.size());
+    for (TsTableColumnSchema columnSchema : columnSchemaList) {
+      if (columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)
+          || 
columnSchema.getColumnCategory().equals(TsTableColumnCategory.ATTRIBUTE)) {
+        columnHeaderList.add(
+            new ColumnHeader(columnSchema.getColumnName(), 
columnSchema.getDataType()));
+      }
+    }
+
+    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaderList, true));
+
+    planBuilder =
+        planBuilder
+            .planTableDeviceSource(
+                statement.getDatabase(),
+                statement.getTableName(),
+                statement.getIdDeterminedFilterList(),
+                statement.getIdFuzzyFilterList(),
+                columnHeaderList)
+            .planSchemaQueryMerge(false);
+
+    return planBuilder.getRoot();
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
index 3b13ac78a9d..cc3326e2cf6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
@@ -173,6 +173,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.Sche
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TableDeviceScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationMergeSortNode;
@@ -3262,4 +3263,25 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
     return new ExplainAnalyzeOperator(
         operatorContext, operator, node.getQueryId(), node.isVerbose(), 
node.getTimeout());
   }
+
+  @Override
+  public Operator visitTableDeviceScan(
+      TableDeviceScanNode node, LocalExecutionPlanContext context) {
+    OperatorContext operatorContext =
+        context
+            .getDriverContext()
+            .addOperatorContext(
+                context.getNextOperatorId(),
+                node.getPlanNodeId(),
+                SchemaQueryScanOperator.class.getSimpleName());
+    return new SchemaQueryScanOperator<>(
+        node.getPlanNodeId(),
+        operatorContext,
+        SchemaSourceFactory.getTableDeviceSchemaSource(
+            node.getDatabase(),
+            node.getTableName(),
+            node.getIdDeterminedFilterList(),
+            node.getIdFuzzyFilterList(),
+            node.getColumnHeaderList()));
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java
index 3ae7a3f126f..0c19a738a5d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java
@@ -33,6 +33,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.Sche
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TableDeviceScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationMergeSortNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.DeviceMergeNode;
@@ -154,6 +155,11 @@ public class ExchangeNodeAdder extends 
PlanVisitor<PlanNode, NodeGroupContext> {
     return processNoChildSourceNode(node, context);
   }
 
+  @Override
+  public PlanNode visitTableDeviceScan(TableDeviceScanNode node, 
NodeGroupContext context) {
+    return processNoChildSourceNode(node, context);
+  }
+
   @Override
   public PlanNode visitSchemaFetchScan(SchemaFetchScanNode node, 
NodeGroupContext context) {
     return processNoChildSourceNode(node, context);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
index 1fa71fe9aa2..a417be3f9b7 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java
@@ -31,6 +31,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.Sche
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TableDeviceScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.ActivateTemplateNode;
@@ -558,4 +559,8 @@ public abstract class PlanVisitor<R, C> {
   public R visitCreateTableDevice(CreateTableDeviceNode node, C context) {
     return visitPlan(node, context);
   }
+
+  public R visitTableDeviceScan(TableDeviceScanNode node, C context) {
+    return visitPlan(node, context);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TableDeviceScanNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TableDeviceScanNode.java
new file mode 100644
index 00000000000..3605963c6bc
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TableDeviceScanNode.java
@@ -0,0 +1,141 @@
+package org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read;
+
+import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class TableDeviceScanNode extends SchemaQueryScanNode {
+
+  private String database;
+
+  private String tableName;
+
+  private List<SchemaFilter> idDeterminedFilterList;
+
+  private List<SchemaFilter> idFuzzyFilterList;
+
+  private List<ColumnHeader> columnHeaderList;
+
+  private TRegionReplicaSet schemaRegionReplicaSet;
+
+  public TableDeviceScanNode(PlanNodeId id) {
+    super(id);
+  }
+
+  public TableDeviceScanNode(
+      PlanNodeId id,
+      String database,
+      String tableName,
+      List<SchemaFilter> idDeterminedFilterList,
+      List<SchemaFilter> idFuzzyFilterList,
+      List<ColumnHeader> columnHeaderList,
+      TRegionReplicaSet regionReplicaSet) {
+    super(id);
+    this.database = database;
+    this.tableName = tableName;
+    this.idDeterminedFilterList = idDeterminedFilterList;
+    this.idFuzzyFilterList = idFuzzyFilterList;
+    this.columnHeaderList = columnHeaderList;
+    this.schemaRegionReplicaSet = regionReplicaSet;
+  }
+
+  public String getDatabase() {
+    return database;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public List<SchemaFilter> getIdDeterminedFilterList() {
+    return idDeterminedFilterList;
+  }
+
+  public List<SchemaFilter> getIdFuzzyFilterList() {
+    return idFuzzyFilterList;
+  }
+
+  public List<ColumnHeader> getColumnHeaderList() {
+    return columnHeaderList;
+  }
+
+  @Override
+  public void open() throws Exception {}
+
+  @Override
+  public void setRegionReplicaSet(TRegionReplicaSet regionReplicaSet) {
+    this.schemaRegionReplicaSet = regionReplicaSet;
+  }
+
+  @Override
+  public void close() throws Exception {}
+
+  @Override
+  public TRegionReplicaSet getRegionReplicaSet() {
+    return schemaRegionReplicaSet;
+  }
+
+  @Override
+  public PlanNode clone() {
+    return new TableDeviceScanNode(
+        getPlanNodeId(),
+        database,
+        tableName,
+        idDeterminedFilterList,
+        idFuzzyFilterList,
+        columnHeaderList,
+        schemaRegionReplicaSet);
+  }
+
+  @Override
+  public List<String> getOutputColumnNames() {
+    return 
columnHeaderList.stream().map(ColumnHeader::getColumnName).collect(Collectors.toList());
+  }
+
+  @Override
+  protected void serializeAttributes(ByteBuffer byteBuffer) {}
+
+  @Override
+  protected void serializeAttributes(DataOutputStream stream) throws 
IOException {}
+
+  @Override
+  public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+    return visitor.visitTableDeviceScan(this, context);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof TableDeviceScanNode)) return false;
+    if (!super.equals(o)) return false;
+    TableDeviceScanNode that = (TableDeviceScanNode) o;
+    return Objects.equals(database, that.database)
+        && Objects.equals(tableName, that.tableName)
+        && Objects.equals(idDeterminedFilterList, that.idDeterminedFilterList)
+        && Objects.equals(idFuzzyFilterList, that.idFuzzyFilterList)
+        && Objects.equals(columnHeaderList, that.columnHeaderList)
+        && Objects.equals(schemaRegionReplicaSet, that.schemaRegionReplicaSet);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(
+        super.hashCode(),
+        database,
+        tableName,
+        idDeterminedFilterList,
+        idFuzzyFilterList,
+        columnHeaderList,
+        schemaRegionReplicaSet);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/schema/TableModelSchemaFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/schema/TableModelSchemaFetcher.java
index ca4c7fee853..231708e71b8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/schema/TableModelSchemaFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/schema/TableModelSchemaFetcher.java
@@ -20,10 +20,19 @@
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer.schema;
 
 import org.apache.iotdb.commons.exception.IoTDBException;
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceAttributeFilter;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceIdFilter;
+import org.apache.iotdb.commons.schema.filter.impl.OrFilter;
+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.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.protocol.session.SessionManager;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
 import org.apache.iotdb.db.queryengine.plan.Coordinator;
 import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
 import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
@@ -31,10 +40,31 @@ import 
org.apache.iotdb.db.queryengine.plan.analyze.schema.ClusterSchemaFetcher;
 import org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.DeviceEntry;
 import 
org.apache.iotdb.db.queryengine.plan.statement.internal.CreateTableDeviceStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTableDevicesStatement;
+import org.apache.iotdb.db.relational.sql.tree.ComparisonExpression;
 import org.apache.iotdb.db.relational.sql.tree.Expression;
+import org.apache.iotdb.db.relational.sql.tree.Identifier;
+import org.apache.iotdb.db.relational.sql.tree.Literal;
+import org.apache.iotdb.db.relational.sql.tree.LogicalExpression;
+import org.apache.iotdb.db.relational.sql.tree.StringLiteral;
+import org.apache.iotdb.db.relational.sql.tree.SymbolReference;
+import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 import org.apache.iotdb.rpc.TSStatusCode;
 
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.file.metadata.IDeviceID;
+import org.apache.tsfile.file.metadata.StringArrayDeviceID;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.utils.Pair;
+
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_SEPARATOR;
 
 public class TableModelSchemaFetcher {
 
@@ -85,6 +115,186 @@ public class TableModelSchemaFetcher {
       String table,
       List<Expression> expressionList,
       List<String> attributeColumns) {
-    return null;
+    List<DeviceEntry> deviceEntryList = new ArrayList<>();
+
+    Coordinator coordinator = Coordinator.getInstance();
+    long queryId = SessionManager.getInstance().requestQueryId();
+    Throwable t = null;
+
+    TsTable tableInstance = 
DataNodeTableCache.getInstance().getTable(database, table);
+    Pair<List<SchemaFilter>, List<SchemaFilter>> filters =
+        transformExpression(expressionList, tableInstance);
+    List<SchemaFilter> idFilters = filters.getLeft();
+    List<SchemaFilter> attributeFilters = filters.getRight();
+    ShowTableDevicesStatement statement =
+        new ShowTableDevicesStatement(database, table, idFilters, 
attributeFilters);
+    ExecutionResult executionResult =
+        Coordinator.getInstance()
+            .executeForTreeModel(
+                statement,
+                queryId,
+                SessionManager.getInstance()
+                    
.getSessionInfo(SessionManager.getInstance().getCurrSession()),
+                "",
+                ClusterPartitionFetcher.getInstance(),
+                ClusterSchemaFetcher.getInstance(),
+                config.getQueryTimeoutThreshold());
+    if (executionResult.status.getCode() != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      throw new RuntimeException(
+          new IoTDBException(
+              executionResult.status.getMessage(), 
executionResult.status.getCode()));
+    }
+
+    List<ColumnHeader> columnHeaderList =
+        
coordinator.getQueryExecution(queryId).getDatasetHeader().getColumnHeaders();
+    int idLength = DataNodeTableCache.getInstance().getTable(database, 
table).getIdNums();
+    Map<String, String> attributeMap;
+
+    try {
+      while (coordinator.getQueryExecution(queryId).hasNextResult()) {
+        Optional<TsBlock> tsBlock;
+        try {
+          tsBlock = coordinator.getQueryExecution(queryId).getBatchResult();
+        } catch (IoTDBException e) {
+          t = e;
+          throw new RuntimeException("Fetch Table Device Schema failed. ", e);
+        }
+        if (!tsBlock.isPresent() || tsBlock.get().isEmpty()) {
+          break;
+        }
+        Column[] columns = tsBlock.get().getValueColumns();
+        for (int i = 0; i < tsBlock.get().getPositionCount(); i++) {
+          String[] nodes = new String[idLength + 1];
+          nodes[0] = database + PATH_SEPARATOR + table;
+          int idIndex = 0;
+          attributeMap = new HashMap<>();
+          for (int j = 0; j < columnHeaderList.size(); j++) {
+            TsTableColumnSchema columnSchema =
+                
tableInstance.getColumnSchema(columnHeaderList.get(j).getColumnName());
+            if 
(columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)) {
+              nodes[idIndex + 1] = columns[j].getBinary(i).toString();
+              idIndex++;
+            } else {
+              attributeMap.put(columnSchema.getColumnName(), 
columns[j].getBinary(i).toString());
+            }
+          }
+          IDeviceID deviceID = new StringArrayDeviceID(nodes);
+          deviceEntryList.add(
+              new DeviceEntry(
+                  deviceID,
+                  
attributeColumns.stream().map(attributeMap::get).collect(Collectors.toList())));
+        }
+      }
+    } catch (Throwable throwable) {
+      t = throwable;
+      throw throwable;
+    } finally {
+      coordinator.cleanupQueryExecution(queryId, null, t);
+    }
+    System.out.println(deviceEntryList);
+    return deviceEntryList;
+  }
+
+  private Pair<List<SchemaFilter>, List<SchemaFilter>> transformExpression(
+      List<Expression> expressionList, TsTable table) {
+    List<SchemaFilter> idDeterminedFilters = new ArrayList<>();
+    List<SchemaFilter> idFuzzyFilters = new ArrayList<>();
+    Map<String, Integer> indexMap = getIdColumnIndex(table);
+    for (Expression expression : expressionList) {
+      if (expression == null) {
+        continue;
+      }
+      if (expression instanceof LogicalExpression) {
+        LogicalExpression logicalExpression = (LogicalExpression) expression;
+        SchemaFilter schemaFilter = transformToSchemaFilter(logicalExpression, 
table, indexMap);
+        if (hasAttribute(schemaFilter)) {
+          idFuzzyFilters.add(schemaFilter);
+        } else {
+          idDeterminedFilters.add(schemaFilter);
+        }
+      } else {
+        SchemaFilter schemaFilter =
+            transformToSchemaFilter((ComparisonExpression) expression, table, 
indexMap);
+        if 
(schemaFilter.getSchemaFilterType().equals(SchemaFilterType.DEVICE_ATTRIBUTE)) {
+          idFuzzyFilters.add(schemaFilter);
+        } else {
+          idDeterminedFilters.add(schemaFilter);
+        }
+      }
+    }
+    return new Pair<>(idDeterminedFilters, idFuzzyFilters);
+  }
+
+  private boolean hasAttribute(SchemaFilter schemaFilter) {
+    if (schemaFilter.getSchemaFilterType().equals(SchemaFilterType.OR)) {
+      return hasAttribute(((OrFilter) schemaFilter).getLeft())
+          || hasAttribute(((OrFilter) schemaFilter).getRight());
+    }
+
+    return 
schemaFilter.getSchemaFilterType().equals(SchemaFilterType.DEVICE_ATTRIBUTE);
+  }
+
+  private SchemaFilter transformToSchemaFilter(
+      LogicalExpression logicalExpression, TsTable table, Map<String, Integer> 
indexMap) {
+    SchemaFilter left;
+    SchemaFilter right;
+    if (logicalExpression.getTerms().get(0) instanceof LogicalExpression) {
+      left =
+          transformToSchemaFilter(
+              (LogicalExpression) (logicalExpression.getChildren().get(0)), 
table, indexMap);
+    } else {
+      left =
+          transformToSchemaFilter(
+              (ComparisonExpression) (logicalExpression.getChildren().get(0)), 
table, indexMap);
+    }
+    if (logicalExpression.getTerms().get(1) instanceof LogicalExpression) {
+      right =
+          transformToSchemaFilter(
+              (LogicalExpression) (logicalExpression.getChildren().get(1)), 
table, indexMap);
+    } else {
+      right =
+          transformToSchemaFilter(
+              (ComparisonExpression) (logicalExpression.getChildren().get(1)), 
table, indexMap);
+    }
+    return new OrFilter(left, right);
+  }
+
+  private SchemaFilter transformToSchemaFilter(
+      ComparisonExpression comparisonExpression, TsTable table, Map<String, 
Integer> indexMap) {
+    String columnName;
+    String value;
+    if (comparisonExpression.getLeft() instanceof Literal) {
+      value = ((StringLiteral) (comparisonExpression.getLeft())).getValue();
+      if (comparisonExpression.getRight() instanceof Identifier) {
+        columnName = ((Identifier) 
(comparisonExpression.getRight())).getValue();
+      } else {
+        columnName = ((SymbolReference) 
(comparisonExpression.getRight())).getName();
+      }
+    } else {
+      value = ((StringLiteral) (comparisonExpression.getRight())).getValue();
+      if (comparisonExpression.getLeft() instanceof Identifier) {
+        columnName = ((Identifier) 
(comparisonExpression.getLeft())).getValue();
+      } else {
+        columnName = ((SymbolReference) 
(comparisonExpression.getLeft())).getName();
+      }
+    }
+    if 
(table.getColumnSchema(columnName).getColumnCategory().equals(TsTableColumnCategory.ID))
 {
+      return new DeviceIdFilter(indexMap.get(columnName), value);
+    } else {
+      return new DeviceAttributeFilter(columnName, value);
+    }
+  }
+
+  private Map<String, Integer> getIdColumnIndex(TsTable table) {
+    Map<String, Integer> map = new HashMap<>();
+    List<TsTableColumnSchema> columnSchemaList = table.getColumnList();
+    int idIndex = 0;
+    for (TsTableColumnSchema columnSchema : columnSchemaList) {
+      if (columnSchema.getColumnCategory().equals(TsTableColumnCategory.ID)) {
+        map.put(columnSchema.getColumnName(), idIndex);
+        idIndex++;
+      }
+    }
+    return map;
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/DeviceEntry.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/DeviceEntry.java
index 81b34e32c8b..cac441ef1f1 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/DeviceEntry.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/DeviceEntry.java
@@ -40,4 +40,14 @@ public class DeviceEntry {
   public List<String> getAttributeColumnValues() {
     return attributeColumnValues;
   }
+
+  @Override
+  public String toString() {
+    return "DeviceEntry{"
+        + "deviceID="
+        + deviceID
+        + ", attributeColumnValues="
+        + attributeColumnValues
+        + '}';
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
index 09947ddcd76..ce0d72e104b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java
@@ -25,6 +25,7 @@ import 
org.apache.iotdb.commons.udf.builtin.BuiltinScalarFunction;
 import org.apache.iotdb.db.exception.metadata.table.TableNotExistsException;
 import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
+import 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.schema.TableModelSchemaFetcher;
 import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
@@ -35,13 +36,9 @@ import org.apache.iotdb.db.relational.sql.tree.Expression;
 import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 import org.apache.iotdb.db.utils.constant.SqlConstant;
 
-import org.apache.tsfile.file.metadata.IDeviceID;
-import org.apache.tsfile.file.metadata.StringArrayDeviceID;
 import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.common.type.TypeFactory;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
@@ -260,13 +257,12 @@ public class TableMetadataImpl implements Metadata {
       QualifiedObjectName tableName,
       List<Expression> expressionList,
       List<String> attributeColumns) {
-    // fixme, perfect the real metadata impl
-    List<DeviceEntry> result = new ArrayList<>();
-    IDeviceID deviceID1 = new StringArrayDeviceID("db.table1", "beijing", 
"a_1");
-    IDeviceID deviceID2 = new StringArrayDeviceID("db.table1", "beijing", 
"b_1");
-    result.add(new DeviceEntry(deviceID1, Arrays.asList("old", "low")));
-    result.add(new DeviceEntry(deviceID2, Arrays.asList("new", "high")));
-    return result;
+    return TableModelSchemaFetcher.getInstance()
+        .fetchDeviceSchema(
+            tableName.getDatabaseName(),
+            tableName.getObjectName(),
+            expressionList,
+            attributeColumns);
   }
 
   public static boolean isTwoNumericType(List<? extends Type> argumentTypes) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
index 0307f9bb0fe..a13551d3164 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java
@@ -83,6 +83,9 @@ public class IndexScan implements RelationalPlanOptimizer {
     @Override
     public PlanNode visitFilter(FilterNode node, RewriterContext context) {
       context.setPredicate(node.getPredicate());
+      for (PlanNode child : node.getChildren()) {
+        child.accept(this, context);
+      }
       return node;
     }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
index acb722fc933..be7f36de3fb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
@@ -71,6 +71,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatem
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowFunctionsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowRegionStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTableDevicesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTriggersStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowVariablesStatement;
@@ -611,4 +612,8 @@ public abstract class StatementVisitor<R, C> {
       CreateTableDeviceStatement createTableDeviceStatement, C context) {
     return visitStatement(createTableDeviceStatement, context);
   }
+
+  public R visitShowTableDevices(ShowTableDevicesStatement statement, C 
context) {
+    return visitStatement(statement, context);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTableDevicesStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTableDevicesStatement.java
new file mode 100644
index 00000000000..0cb634830cd
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTableDevicesStatement.java
@@ -0,0 +1,69 @@
+/*
+ * 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.statement.metadata;
+
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
+
+import java.util.List;
+
+public class ShowTableDevicesStatement extends ShowStatement {
+
+  private final String database;
+
+  private final String tableName;
+
+  private final List<SchemaFilter> idDeterminedFilterList;
+
+  private final List<SchemaFilter> idFuzzyFilterList;
+
+  public ShowTableDevicesStatement(
+      String database,
+      String tableName,
+      List<SchemaFilter> idDeterminedFilterList,
+      List<SchemaFilter> idFuzzyFilterList) {
+    super();
+    this.database = database;
+    this.tableName = tableName;
+    this.idDeterminedFilterList = idDeterminedFilterList;
+    this.idFuzzyFilterList = idFuzzyFilterList;
+  }
+
+  public String getDatabase() {
+    return database;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public List<SchemaFilter> getIdDeterminedFilterList() {
+    return idDeterminedFilterList;
+  }
+
+  public List<SchemaFilter> getIdFuzzyFilterList() {
+    return idFuzzyFilterList;
+  }
+
+  @Override
+  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+    return visitor.visitShowTableDevices(this, context);
+  }
+}
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 43120723863..a8f814d4a9c 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,6 +32,7 @@ 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;
@@ -314,5 +315,7 @@ public interface ISchemaRegion {
   ISchemaReader<INodeSchemaInfo> getNodeReader(IShowNodesPlan showNodesPlan)
       throws MetadataException;
 
+  ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(ShowTableDevicesPlan 
showTableDevicesPlan)
+      throws MetadataException;
   // endregion
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/DeviceAttributeStore.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/DeviceAttributeStore.java
index 048d6eb5285..6a65fe17f1a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/DeviceAttributeStore.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/DeviceAttributeStore.java
@@ -120,12 +120,17 @@ public class DeviceAttributeStore implements 
IDeviceAttributeStore {
 
   @Override
   public void alterAttribute(int pointer, List<String> nameList, List<String> 
valueList) {
-    Map<String, String> attributeMap = deviceAttributeList.get((int) pointer);
+    Map<String, String> attributeMap = deviceAttributeList.get(pointer);
     for (int i = 0; i < nameList.size(); i++) {
       attributeMap.put(nameList.get(i), valueList.get(i));
     }
   }
 
+  @Override
+  public String getAttribute(int pointer, String name) {
+    return deviceAttributeList.get(pointer).get(name);
+  }
+
   private void serialize(OutputStream outputStream) throws IOException {
     ReadWriteIOUtils.write(deviceAttributeList.size(), outputStream);
     for (Map<String, String> attributeMap : deviceAttributeList) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/IDeviceAttributeStore.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/IDeviceAttributeStore.java
index c5395a93a67..79f44d20bd2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/IDeviceAttributeStore.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/attribute/IDeviceAttributeStore.java
@@ -34,4 +34,6 @@ public interface IDeviceAttributeStore {
   int createAttribute(List<String> nameList, List<String> valueList);
 
   void alterAttribute(int pointer, List<String> nameList, List<String> 
valueList);
+
+  String getAttribute(int pointer, String name);
 }
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 13913fbb2ec..3aae464def1 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,6 +62,7 @@ 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;
@@ -1245,7 +1246,8 @@ public class SchemaRegionMemoryImpl implements 
ISchemaRegion {
   @Override
   public ISchemaReader<IDeviceSchemaInfo> getDeviceReader(IShowDevicesPlan 
showDevicesPlan)
       throws MetadataException {
-    return mtree.getDeviceReader(showDevicesPlan);
+    return mtree.getDeviceReader(
+        showDevicesPlan, (pointer, name) -> 
deviceAttributeStore.getAttribute(pointer, name));
   }
 
   @Override
@@ -1275,6 +1277,15 @@ public class SchemaRegionMemoryImpl implements 
ISchemaRegion {
     return mtree.getNodeReader(showNodesPlan);
   }
 
+  @Override
+  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
+      ShowTableDevicesPlan showTableDevicesPlan) throws MetadataException {
+    return mtree.getDeviceReader(
+        showTableDevicesPlan.getDevicePattern(),
+        showTableDevicesPlan.getAttributeFilter(),
+        (pointer, name) -> deviceAttributeStore.getAttribute(pointer, name));
+  }
+
   // endregion
 
   private static class RecoverOperationResult {
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 f0095babf9a..6cd1fcd1f93 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,6 +63,7 @@ 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;
@@ -1354,6 +1355,12 @@ public class SchemaRegionPBTreeImpl implements 
ISchemaRegion {
       throws MetadataException {
     return mtree.getNodeReader(showNodesPlan);
   }
+
+  @Override
+  public ISchemaReader<IDeviceSchemaInfo> getTableDeviceReader(
+      ShowTableDevicesPlan showTableDevicesPlan) {
+    throw new UnsupportedOperationException();
+  }
   // endregion
 
   private static class RecoverOperationResult {
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 3c453801c7d..d78b8325a37 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
@@ -25,6 +25,7 @@ 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;
@@ -91,6 +92,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntConsumer;
@@ -951,7 +953,8 @@ public class MTreeBelowSGMemoryImpl {
   // region Interfaces for schema reader
 
   @SuppressWarnings("java:S2095")
-  public ISchemaReader<IDeviceSchemaInfo> getDeviceReader(IShowDevicesPlan 
showDevicesPlan)
+  public ISchemaReader<IDeviceSchemaInfo> getDeviceReader(
+      IShowDevicesPlan showDevicesPlan, BiFunction<Integer, String, String> 
attributeProvider)
       throws MetadataException {
     EntityCollector<IDeviceSchemaInfo, IMemMNode> collector =
         new EntityCollector<IDeviceSchemaInfo, IMemMNode>(
@@ -963,8 +966,15 @@ public class MTreeBelowSGMemoryImpl {
 
           protected IDeviceSchemaInfo collectEntity(IDeviceMNode<IMemMNode> 
node) {
             PartialPath device = 
getPartialPathFromRootToNode(node.getAsMNode());
-            return new ShowDevicesResult(
-                device.getFullPath(), node.isAlignedNullable(), 
node.getSchemaTemplateId());
+            ShowDevicesResult result =
+                new ShowDevicesResult(
+                    device.getFullPath(), node.isAlignedNullable(), 
node.getSchemaTemplateId());
+            result.setAttributeProvider(
+                k ->
+                    attributeProvider.apply(
+                        ((TableDeviceInfo<IMemMNode>) 
node.getDeviceInfo()).getAttributePointer(),
+                        k));
+            return result;
           }
         };
     if (showDevicesPlan.usingSchemaTemplate()) {
@@ -995,7 +1005,8 @@ public class MTreeBelowSGMemoryImpl {
           public boolean hasNext() {
             while (next == null && collector.hasNext()) {
               IDeviceSchemaInfo temp = collector.next();
-              if (filterVisitor.process(showDevicesPlan.getSchemaFilter(), 
temp)) {
+              if (showDevicesPlan.getSchemaFilter() == null
+                  || filterVisitor.process(showDevicesPlan.getSchemaFilter(), 
temp)) {
                 next = temp;
               }
             }
@@ -1019,6 +1030,69 @@ public class MTreeBelowSGMemoryImpl {
     }
   }
 
+  public ISchemaReader<IDeviceSchemaInfo> getDeviceReader(
+      PartialPath pattern,
+      SchemaFilter attributeFilter,
+      BiFunction<Integer, String, String> attributeProvider)
+      throws MetadataException {
+    EntityCollector<IDeviceSchemaInfo, IMemMNode> collector =
+        new EntityCollector<IDeviceSchemaInfo, IMemMNode>(rootNode, pattern, 
store, false, null) {
+
+          protected IDeviceSchemaInfo collectEntity(IDeviceMNode<IMemMNode> 
node) {
+            PartialPath device = 
getPartialPathFromRootToNode(node.getAsMNode());
+            ShowDevicesResult result =
+                new ShowDevicesResult(
+                    device.getFullPath(), node.isAlignedNullable(), 
node.getSchemaTemplateId());
+            result.setAttributeProvider(
+                k ->
+                    attributeProvider.apply(
+                        ((TableDeviceInfo<IMemMNode>) 
node.getDeviceInfo()).getAttributePointer(),
+                        k));
+            return result;
+          }
+        };
+    return new ISchemaReader<IDeviceSchemaInfo>() {
+
+      private final DeviceFilterVisitor filterVisitor = new 
DeviceFilterVisitor();
+      private IDeviceSchemaInfo next;
+
+      public boolean isSuccess() {
+        return collector.isSuccess();
+      }
+
+      public Throwable getFailure() {
+        return collector.getFailure();
+      }
+
+      public void close() {
+        collector.close();
+      }
+
+      public ListenableFuture<?> isBlocked() {
+        return NOT_BLOCKED;
+      }
+
+      public boolean hasNext() {
+        while (next == null && collector.hasNext()) {
+          IDeviceSchemaInfo temp = collector.next();
+          if (attributeFilter == null || 
filterVisitor.process(attributeFilter, temp)) {
+            next = temp;
+          }
+        }
+        return next != null;
+      }
+
+      public IDeviceSchemaInfo next() {
+        if (!hasNext()) {
+          throw new NoSuchElementException();
+        }
+        IDeviceSchemaInfo result = next;
+        next = null;
+        return result;
+      }
+    };
+  }
+
   public ISchemaReader<ITimeSeriesSchemaInfo> getTimeSeriesReader(
       IShowTimeSeriesPlan showTimeSeriesPlan,
       Function<Long, Pair<Map<String, String>, Map<String, String>>> 
tagAndAttributeProvider)
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/req/impl/ShowTableDevicesPlan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/req/impl/ShowTableDevicesPlan.java
new file mode 100644
index 00000000000..d3af79e093d
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/req/impl/ShowTableDevicesPlan.java
@@ -0,0 +1,40 @@
+package org.apache.iotdb.db.schemaengine.schemaregion.read.req.impl;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.impl.AndFilter;
+
+import java.util.List;
+
+public class ShowTableDevicesPlan {
+
+  private PartialPath devicePattern;
+
+  private SchemaFilter attributeFilter;
+
+  public ShowTableDevicesPlan(PartialPath devicePattern, List<SchemaFilter> 
attributeFilterList) {
+    this.devicePattern = devicePattern;
+    this.attributeFilter = getAttributeFilter(attributeFilterList);
+  }
+
+  private SchemaFilter getAttributeFilter(List<SchemaFilter> filterList) {
+    if (filterList.isEmpty()) {
+      return null;
+    }
+    AndFilter andFilter;
+    SchemaFilter latestFilter = filterList.get(0);
+    for (int i = 1; i < filterList.size(); i++) {
+      andFilter = new AndFilter(latestFilter, filterList.get(i));
+      latestFilter = andFilter;
+    }
+    return latestFilter;
+  }
+
+  public PartialPath getDevicePattern() {
+    return devicePattern;
+  }
+
+  public SchemaFilter getAttributeFilter() {
+    return attributeFilter;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/IDeviceSchemaInfo.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/IDeviceSchemaInfo.java
index 9a670f9b44b..634f7d65461 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/IDeviceSchemaInfo.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/read/resp/info/IDeviceSchemaInfo.java
@@ -24,4 +24,6 @@ public interface IDeviceSchemaInfo extends ISchemaInfo {
   Boolean isAligned();
 
   int getTemplateId();
+
+  String getAttributeValue(String attributeKey);
 }
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 19aa1971008..8f4c5b95a6b 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
@@ -21,11 +21,14 @@ package 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.impl;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
 
 import java.util.Objects;
+import java.util.function.Function;
 
 public class ShowDevicesResult extends ShowSchemaResult implements 
IDeviceSchemaInfo {
   private Boolean isAligned;
   private int templateId;
 
+  private Function<String, String> attributeProvider;
+
   public ShowDevicesResult(String name, Boolean isAligned, int templateId) {
     super(name);
     this.isAligned = isAligned;
@@ -40,6 +43,15 @@ public class ShowDevicesResult extends ShowSchemaResult 
implements IDeviceSchema
     return templateId;
   }
 
+  public void setAttributeProvider(Function<String, String> attributeProvider) 
{
+    this.attributeProvider = attributeProvider;
+  }
+
+  @Override
+  public String getAttributeValue(String attributeKey) {
+    return attributeProvider.apply(attributeKey);
+  }
+
   @Override
   public String toString() {
     return "ShowDevicesResult{"
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/filter/DeviceFilterVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/filter/DeviceFilterVisitor.java
index e1723193abf..0555aecf5ea 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/filter/DeviceFilterVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/filter/DeviceFilterVisitor.java
@@ -21,6 +21,8 @@ package 
org.apache.iotdb.db.schemaengine.schemaregion.utils.filter;
 
 import org.apache.iotdb.commons.schema.filter.SchemaFilter;
 import org.apache.iotdb.commons.schema.filter.SchemaFilterVisitor;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceAttributeFilter;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceIdFilter;
 import org.apache.iotdb.commons.schema.filter.impl.PathContainsFilter;
 import org.apache.iotdb.commons.schema.filter.impl.TemplateFilter;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.IDeviceSchemaInfo;
@@ -59,4 +61,14 @@ public class DeviceFilterVisitor extends 
SchemaFilterVisitor<IDeviceSchemaInfo>
       return false;
     }
   }
+
+  @Override
+  public boolean visitDeviceIdFilter(DeviceIdFilter filter, IDeviceSchemaInfo 
info) {
+    return info.getPartialPath().getNodes()[filter.getIndex() + 
3].equals(filter.getValue());
+  }
+
+  @Override
+  public boolean visitDeviceAttributeFilter(DeviceAttributeFilter filter, 
IDeviceSchemaInfo info) {
+    return info.getAttributeValue(filter.getKey()).equals(filter.getValue());
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterType.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterType.java
index 285130f778e..66e9f15e939 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterType.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterType.java
@@ -26,6 +26,11 @@ public enum SchemaFilterType {
   VIEW_TYPE((short) 4),
   AND((short) 5),
   TEMPLATE_FILTER((short) 6),
+
+  DEVICE_ID((short) 7),
+  DEVICE_ATTRIBUTE((short) 8),
+
+  OR((short) 9),
   ;
 
   private final short code;
@@ -54,6 +59,12 @@ public enum SchemaFilterType {
         return AND;
       case 6:
         return TEMPLATE_FILTER;
+      case 7:
+        return DEVICE_ID;
+      case 8:
+        return DEVICE_ATTRIBUTE;
+      case 9:
+        return OR;
       default:
         throw new IllegalArgumentException("Invalid input: " + code);
     }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterVisitor.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterVisitor.java
index d6861baab68..f503da64b15 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterVisitor.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/SchemaFilterVisitor.java
@@ -20,6 +20,9 @@ package org.apache.iotdb.commons.schema.filter;
 
 import org.apache.iotdb.commons.schema.filter.impl.AndFilter;
 import org.apache.iotdb.commons.schema.filter.impl.DataTypeFilter;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceAttributeFilter;
+import org.apache.iotdb.commons.schema.filter.impl.DeviceIdFilter;
+import org.apache.iotdb.commons.schema.filter.impl.OrFilter;
 import org.apache.iotdb.commons.schema.filter.impl.PathContainsFilter;
 import org.apache.iotdb.commons.schema.filter.impl.TagFilter;
 import org.apache.iotdb.commons.schema.filter.impl.TemplateFilter;
@@ -69,4 +72,16 @@ public abstract class SchemaFilterVisitor<C> {
   public boolean visitAndFilter(AndFilter andFilter, C context) {
     return andFilter.getLeft().accept(this, context) && 
andFilter.getRight().accept(this, context);
   }
+
+  public boolean visitOrFilter(OrFilter orFilter, C context) {
+    return orFilter.getLeft().accept(this, context) || 
orFilter.getRight().accept(this, context);
+  }
+
+  public boolean visitDeviceIdFilter(DeviceIdFilter filter, C context) {
+    return visitFilter(filter, context);
+  }
+
+  public boolean visitDeviceAttributeFilter(DeviceAttributeFilter filter, C 
context) {
+    return visitDeviceAttributeFilter(filter, context);
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceAttributeFilter.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceAttributeFilter.java
new file mode 100644
index 00000000000..09736bf5b19
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceAttributeFilter.java
@@ -0,0 +1,63 @@
+/*
+ * 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.commons.schema.filter.impl;
+
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class DeviceAttributeFilter extends SchemaFilter {
+
+  private final String key;
+
+  private final String value;
+
+  public DeviceAttributeFilter(String key, String value) {
+    this.key = key;
+    this.value = value;
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  @Override
+  public <C> boolean accept(SchemaFilterVisitor<C> visitor, C node) {
+    return visitor.visitDeviceAttributeFilter(this, node);
+  }
+
+  @Override
+  public SchemaFilterType getSchemaFilterType() {
+    return SchemaFilterType.DEVICE_ATTRIBUTE;
+  }
+
+  @Override
+  public void serialize(ByteBuffer byteBuffer) {}
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {}
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceIdFilter.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceIdFilter.java
new file mode 100644
index 00000000000..eda64d90a8d
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/DeviceIdFilter.java
@@ -0,0 +1,63 @@
+/*
+ * 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.commons.schema.filter.impl;
+
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class DeviceIdFilter extends SchemaFilter {
+
+  private final int index;
+
+  private final String value;
+
+  public DeviceIdFilter(int index, String value) {
+    this.index = index;
+    this.value = value;
+  }
+
+  public int getIndex() {
+    return index;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  @Override
+  public <C> boolean accept(SchemaFilterVisitor<C> visitor, C node) {
+    return visitor.visitDeviceIdFilter(this, node);
+  }
+
+  @Override
+  public SchemaFilterType getSchemaFilterType() {
+    return SchemaFilterType.DEVICE_ID;
+  }
+
+  @Override
+  public void serialize(ByteBuffer byteBuffer) {}
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {}
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/OrFilter.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/OrFilter.java
new file mode 100644
index 00000000000..1f57622719d
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/OrFilter.java
@@ -0,0 +1,74 @@
+/*
+ * 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.commons.schema.filter.impl;
+
+import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
+import org.apache.iotdb.commons.schema.filter.SchemaFilterVisitor;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class OrFilter extends SchemaFilter {
+  private final SchemaFilter left;
+  private final SchemaFilter right;
+
+  public OrFilter(SchemaFilter left, SchemaFilter right) {
+    // left and right should not be null
+    this.left = left;
+    this.right = right;
+  }
+
+  public OrFilter(ByteBuffer byteBuffer) {
+    this.left = SchemaFilter.deserialize(byteBuffer);
+    this.right = SchemaFilter.deserialize(byteBuffer);
+  }
+
+  public SchemaFilter getLeft() {
+    return left;
+  }
+
+  public SchemaFilter getRight() {
+    return right;
+  }
+
+  @Override
+  public <C> boolean accept(SchemaFilterVisitor<C> visitor, C node) {
+    return visitor.visitOrFilter(this, node);
+  }
+
+  @Override
+  public SchemaFilterType getSchemaFilterType() {
+    return SchemaFilterType.AND;
+  }
+
+  @Override
+  public void serialize(ByteBuffer byteBuffer) {
+    left.serialize(byteBuffer);
+    right.serialize(byteBuffer);
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    left.serialize(stream);
+    right.serialize(stream);
+  }
+}
diff --git 
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/parser/AstBuilder.java
 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/parser/AstBuilder.java
index 7fbc148ffdb..760b364bbe8 100644
--- 
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/parser/AstBuilder.java
+++ 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/parser/AstBuilder.java
@@ -101,6 +101,7 @@ import org.apache.iotdb.db.relational.sql.tree.Select;
 import org.apache.iotdb.db.relational.sql.tree.SelectItem;
 import org.apache.iotdb.db.relational.sql.tree.SetProperties;
 import org.apache.iotdb.db.relational.sql.tree.ShowDB;
+import org.apache.iotdb.db.relational.sql.tree.ShowDevice;
 import org.apache.iotdb.db.relational.sql.tree.ShowIndex;
 import org.apache.iotdb.db.relational.sql.tree.ShowTables;
 import org.apache.iotdb.db.relational.sql.tree.SimpleCaseExpression;
@@ -382,7 +383,8 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
 
   @Override
   public Node 
visitShowDevicesStatement(RelationalSqlParser.ShowDevicesStatementContext ctx) {
-    return super.visitShowDevicesStatement(ctx);
+    // todo parse where clause
+    return new ShowDevice(getLocation(ctx));
   }
 
   @Override
diff --git 
a/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/ShowDevice.java
 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/ShowDevice.java
new file mode 100644
index 00000000000..4427238fe9a
--- /dev/null
+++ 
b/iotdb-core/relational-parser/src/main/java/org/apache/iotdb/db/relational/sql/tree/ShowDevice.java
@@ -0,0 +1,67 @@
+/*
+ * 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.relational.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+
+public class ShowDevice extends Statement {
+
+  private Expression whereClause;
+
+  public ShowDevice(@Nullable NodeLocation location) {
+    super(location);
+  }
+
+  public void setWhereClause(Expression whereClause) {
+    this.whereClause = whereClause;
+  }
+
+  public Expression getWhereClause() {
+    return whereClause;
+  }
+
+  @Override
+  public List<? extends Node> getChildren() {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public int hashCode() {
+    return getClass().hashCode();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof ShowDevice)) return false;
+    ShowDevice that = (ShowDevice) o;
+    return Objects.equals(whereClause, that.whereClause);
+  }
+
+  @Override
+  public String toString() {
+    return "ShowDevice{" + "whereClause=" + whereClause + '}';
+  }
+}


Reply via email to