You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by xi...@apache.org on 2022/07/06 05:37:47 UTC

[iotdb] branch master updated: [IOTDB-3696] Transport Schema Related IT (#6530)

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

xingtanzjr 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 e1ceaa20b0 [IOTDB-3696] Transport Schema Related IT (#6530)
e1ceaa20b0 is described below

commit e1ceaa20b07966bfa393c147b049e4f33be91c0e
Author: Marcos_Zyk <38...@users.noreply.github.com>
AuthorDate: Wed Jul 6 13:37:43 2022 +0800

    [IOTDB-3696] Transport Schema Related IT (#6530)
---
 .../confignode/persistence/ClusterSchemaInfo.java  |    4 +-
 .../thrift/ConfigNodeRPCServiceProcessorTest.java  |    2 +-
 .../org/apache/iotdb/itbase/env/BaseConfig.java    |   16 +
 .../org/apache/iotdb/db/it/IoTDBCompleteIT.java    |  495 +++++++++
 .../org/apache/iotdb/db/it}/IoTDBDeletionIT.java   |   85 +-
 .../org/apache/iotdb/db/it/IoTDBMultiDeviceIT.java |  297 +++++
 .../it/IoTDBSameMeasurementsDifferentTypesIT.java  |  180 +++
 .../org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java | 1133 +++++++++++++++++++
 .../db/it/aligned/IoTDBAlignedDataDeletionIT.java  |   86 +-
 .../db/it/aligned/IoTDBInsertAlignedValuesIT.java  |    1 +
 .../iotdb/db/it/env/StandaloneEnvConfig.java       |    5 +
 .../db/it/schema/IoTDBAutoCreateSchemaIT.java      |  203 ++++
 .../it/schema/IoTDBCreateAlignedTimeseriesIT.java  |  144 +++
 .../db/it/schema}/IoTDBCreateStorageGroupIT.java   |   36 +-
 .../it/{ => schema}/IoTDBCreateTimeseriesIT.java   |    2 +-
 .../db/it/schema/IoTDBDeleteStorageGroupIT.java    |  176 +++
 .../iotdb/db/it/schema/IoTDBMetadataFetchIT.java   |  553 ++++++++++
 .../db/it/schema/IoTDBSortedShowTimeseriesIT.java  |  334 ++++++
 .../apache/iotdb/db/it/schema/IoTDBTagAlterIT.java |  600 ++++++++++
 .../org/apache/iotdb/db/it/schema/IoTDBTagIT.java  | 1153 ++++++++++++++++++++
 .../db/integration/IoTDBCreateStorageGroupIT.java  |    4 +-
 .../iotdb/db/integration/IoTDBDeletionIT.java      |    4 +-
 .../db/integration/aligned/IoTDBDeletionIT.java    |    4 +-
 .../apache/iotdb/db/engine/StorageEngineV2.java    |    4 +-
 .../metadata/StorageGroupAlreadySetException.java  |    4 +-
 .../mpp/FragmentInstanceDispatchException.java     |   13 +
 .../db/metadata/schemaregion/SchemaEngine.java     |    5 +-
 .../metadata/visitor/SchemaExecutionVisitor.java   |    6 +-
 .../iotdb/db/mpp/execution/QueryStateMachine.java  |   14 +
 .../schema/NodeManageMemoryMergeOperator.java      |   36 +-
 .../operator/schema/NodePathsCountOperator.java    |   23 +-
 .../schema/NodePathsSchemaScanOperator.java        |    3 +-
 .../operator/schema/SchemaFetchMergeOperator.java  |    2 +-
 .../operator/schema/SchemaQueryMergeOperator.java  |    2 +-
 .../schema/SchemaQueryOrderByHeatOperator.java     |   55 +-
 .../schema/TimeSeriesSchemaScanOperator.java       |   14 +-
 .../apache/iotdb/db/mpp/plan/analyze/Analyzer.java |    4 +
 .../plan/analyze/StandalonePartitionFetcher.java   |   40 +-
 .../db/mpp/plan/execution/QueryExecution.java      |    4 +
 .../memory/StatementMemorySourceVisitor.java       |   40 +-
 .../iotdb/db/mpp/plan/planner/LogicalPlanner.java  |   20 +-
 .../planner/plan/node/write/DeleteDataNode.java    |   38 +-
 .../db/mpp/plan/scheduler/ClusterScheduler.java    |    7 +-
 .../plan/scheduler/FragInstanceDispatchResult.java |   13 +
 .../scheduler/FragmentInstanceDispatcherImpl.java  |   32 +-
 .../db/mpp/plan/scheduler/StandaloneScheduler.java |   17 +-
 .../influxdb/meta/InfluxDBMetaManager.java         |    3 +-
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    |    6 +-
 .../impl/DataNodeInternalRPCServiceImpl.java       |   21 +-
 .../service/thrift/impl/InfluxDBServiceImpl.java   |    3 +-
 .../schema/SchemaQueryScanOperatorTest.java        |    3 +-
 .../iotdb/db/mpp/plan/plan/LogicalPlannerTest.java |    8 +-
 .../iotdb/db/qp/logical/LogicalPlanSmallTest.java  |    5 +-
 thrift/src/main/thrift/datanode.thrift             |    1 +
 54 files changed, 5724 insertions(+), 239 deletions(-)

diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfo.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfo.java
index 7691b71ebb..7053f405a9 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfo.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfo.java
@@ -152,7 +152,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
     storageGroupReadWriteLock.readLock().lock();
     try {
       PartialPath patternPath = new PartialPath(plan.getStorageGroupPattern());
-      result.setCount(mTree.getBelongedStorageGroups(patternPath).size());
+      result.setCount(mTree.getStorageGroupNum(patternPath, false));
       result.setStatus(new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()));
     } catch (MetadataException e) {
       LOGGER.error("Error StorageGroup name", e);
@@ -172,7 +172,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
     try {
       Map<String, TStorageGroupSchema> schemaMap = new HashMap<>();
       PartialPath patternPath = new PartialPath(plan.getStorageGroupPattern());
-      List<PartialPath> matchedPaths = mTree.getBelongedStorageGroups(patternPath);
+      List<PartialPath> matchedPaths = mTree.getMatchedStorageGroups(patternPath, false);
       for (PartialPath path : matchedPaths) {
         schemaMap.put(
             path.getFullPath(),
diff --git a/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java b/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
index 945c591506..b725561597 100644
--- a/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
+++ b/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
@@ -314,7 +314,7 @@ public class ConfigNodeRPCServiceProcessorTest {
     Assert.assertEquals(2, countResp.getCount());
 
     // test count one StorageGroup
-    countResp = processor.countMatchedStorageGroups(Arrays.asList("root", "sg0", "**"));
+    countResp = processor.countMatchedStorageGroups(Arrays.asList("root", "sg0"));
     Assert.assertEquals(
         TSStatusCode.SUCCESS_STATUS.getStatusCode(), countResp.getStatus().getCode());
     Assert.assertEquals(1, countResp.getCount());
diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseConfig.java b/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseConfig.java
index 3beaec5b3b..e538c319a4 100644
--- a/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseConfig.java
@@ -38,18 +38,34 @@ public interface BaseConfig {
     return this;
   }
 
+  default int getPageSizeInByte() {
+    return 64 * 1024;
+  }
+
   default BaseConfig setPageSizeInByte(int pageSizeInByte) {
     return this;
   }
 
+  default int getGroupSizeInByte() {
+    return 128 * 1024 * 1024;
+  }
+
   default BaseConfig setGroupSizeInByte(int groupSizeInByte) {
     return this;
   }
 
+  default long getMemtableSizeThreshold() {
+    return 1024 * 1024 * 1024L;
+  }
+
   default BaseConfig setMemtableSizeThreshold(long memtableSizeThreshold) {
     return this;
   }
 
+  default int getDataRegionNum() {
+    return 1;
+  }
+
   default BaseConfig setDataRegionNum(int dataRegionNum) {
     return this;
   }
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java
new file mode 100644
index 0000000000..fd6678b29f
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCompleteIT.java
@@ -0,0 +1,495 @@
+/*
+ * 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.it;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@Ignore
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBCompleteIT {
+  private int prevDataRegionNum;
+
+  @Before
+  public void setUp() throws InterruptedException {
+    // test different partition
+    prevDataRegionNum = ConfigFactory.getConfig().getDataRegionNum();
+    ConfigFactory.getConfig().setDataRegionNum(16);
+    EnvFactory.getEnv().initBeforeClass();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterClass();
+    ConfigFactory.getConfig().setDataRegionNum(prevDataRegionNum);
+  }
+
+  @Ignore
+  @Test
+  public void test() {
+    String[] sqls = {"SET STORAGE GROUP TO root.vehicle"};
+    executeSQL(sqls);
+    // simpleTest();
+    //    insertTest();
+    // selectTest();
+    deleteTest();
+    //    groupByTest();
+    //    funcTest();
+
+    //    funcTestWithOutTimeGenerator();
+  }
+
+  public void simpleTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "SHOW TIMESERIES",
+      "===  Timeseries Tree  ===\n"
+          + "\n"
+          + "{\n"
+          + "\t\"root\":{\n"
+          + "\t\t\"vehicle\":{\n"
+          + "\t\t\t\"d0\":{\n"
+          + "\t\t\t\t\"s0\":{\n"
+          + "\t\t\t\t\t\"args\":\"{}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t}\n"
+          + "\t\t}\n"
+          + "\t}\n"
+          + "}",
+      "DELETE TIMESERIES root.vehicle.d0.s0",
+      "SHOW TIMESERIES",
+      "===  Timeseries Tree  ===\n"
+          + "\n"
+          + "{\n"
+          + "\t\"root\":{\n"
+          + "\t\t\"vehicle\":{}\n"
+          + "\t}\n"
+          + "}",
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=BOOLEAN,ENCODING=PLAIN",
+      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT64,ENCODING=TS_2DIFF",
+      "CREATE TIMESERIES root.vehicle.d0.s2 WITH DATATYPE=FLOAT,ENCODING=GORILLA",
+      "CREATE TIMESERIES root.vehicle.d0.s4 WITH DATATYPE=DOUBLE,ENCODING=RLE",
+      "CREATE TIMESERIES root.vehicle.d1.s5 WITH DATATYPE=TEXT,ENCODING=PLAIN",
+      "CREATE TIMESERIES root.vehicle.d2.s6 WITH DATATYPE=INT32,ENCODING=TS_2DIFF,compressor=UNCOMPRESSED",
+      "CREATE TIMESERIES root.vehicle.d3.s7 WITH DATATYPE=INT32,ENCODING=RLE,compressor=SNAPPY",
+      "CREATE TIMESERIES root.vehicle.d4.s8 WITH DATATYPE=INT32,ENCODING=RLE,MAX_POINT_NUMBER=100",
+      "CREATE TIMESERIES root.vehicle.d5.s9 WITH DATATYPE=FLOAT,ENCODING=PLAIN,compressor=SNAPPY,MAX_POINT_NUMBER=10",
+      "CREATE TIMESERIES root.vehicle.d6.s10 WITH DATATYPE=DOUBLE,ENCODING=RLE,compressor=UNCOMPRESSED,MAX_POINT_NUMBER=10",
+      "DELETE TIMESERIES root.vehicle.d0.**",
+      "SHOW TIMESERIES",
+      "===  Timeseries Tree  ===\n"
+          + "\n"
+          + "{\n"
+          + "\t\"root\":{\n"
+          + "\t\t\"vehicle\":{\n"
+          + "\t\t\t\"d4\":{\n"
+          + "\t\t\t\t\"s8\":{\n"
+          + "\t\t\t\t\t\"args\":\"{max_point_number=100}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t},\n"
+          + "\t\t\t\"d5\":{\n"
+          + "\t\t\t\t\"s9\":{\n"
+          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"FLOAT\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t},\n"
+          + "\t\t\t\"d6\":{\n"
+          + "\t\t\t\t\"s10\":{\n"
+          + "\t\t\t\t\t\"args\":\"{max_point_number=10}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"DOUBLE\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t},\n"
+          + "\t\t\t\"d1\":{\n"
+          + "\t\t\t\t\"s5\":{\n"
+          + "\t\t\t\t\t\"args\":\"{}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"TEXT\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"PLAIN\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t},\n"
+          + "\t\t\t\"d2\":{\n"
+          + "\t\t\t\t\"s6\":{\n"
+          + "\t\t\t\t\t\"args\":\"{}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"UNCOMPRESSED\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"TS_2DIFF\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t},\n"
+          + "\t\t\t\"d3\":{\n"
+          + "\t\t\t\t\"s7\":{\n"
+          + "\t\t\t\t\t\"args\":\"{}\",\n"
+          + "\t\t\t\t\t\"StorageGroup\":\"root.vehicle\",\n"
+          + "\t\t\t\t\t\"DataType\":\"INT32\",\n"
+          + "\t\t\t\t\t\"Compressor\":\"SNAPPY\",\n"
+          + "\t\t\t\t\t\"Encoding\":\"RLE\"\n"
+          + "\t\t\t\t}\n"
+          + "\t\t\t}\n"
+          + "\t\t}\n"
+          + "\t}\n"
+          + "}",
+      "DELETE TIMESERIES root.vehicle.**",
+      "SHOW TIMESERIES",
+      "===  Timeseries Tree  ===\n"
+          + "\n"
+          + "{\n"
+          + "\t\"root\":{\n"
+          + "\t\t\"vehicle\":{}\n"
+          + "\t}\n"
+          + "}"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void insertTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
+      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
+      "SELECT * FROM root.vehicle.d0",
+      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void deleteTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
+      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0,s1) values(2,102,202)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,105)",
+      "SELECT * FROM root.vehicle.d0",
+      "1,101,null,\n" + "2,102,202,\n" + "946684800000,105,null,\n" + "NOW(),104,null,\n",
+      "DELETE TIMESERIES root.vehicle.**",
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,1)",
+      "SELECT * FROM root.vehicle.d0",
+      "1,1,\n" + "2,1,\n" + "3,1,\n" + "4,1,\n" + "5,1,\n" + "6,1,\n" + "7,1,\n" + "8,1,\n"
+          + "9,1,\n" + "10,1,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time < 8",
+      "SELECT * FROM root.vehicle.d0",
+      "8,1,\n" + "9,1,\n" + "10,1,\n",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2000-01-01T08:00:00+08:00,1)",
+      "SELECT * FROM root.vehicle.d0",
+      "8,1,\n" + "9,1,\n" + "10,1,\n" + "946684800000,1,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time < 2000-01-02T08:00:00+08:00",
+      "SELECT * FROM root.vehicle.d0",
+      "",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),1)",
+      "SELECT * FROM root.vehicle.d0",
+      "NOW(),1,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
+      "SELECT * FROM root.vehicle.d0",
+      "",
+      "CREATE TIMESERIES root.vehicle.d1.s1 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,1)",
+      "INSERT INTO root.vehicle.d1(timestamp,s1) values(1,1)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,5)",
+      "INSERT INTO root.vehicle.d1(timestamp,s1) values(5,5)",
+      "SELECT * FROM root.vehicle.*",
+      "1,1,1,\n" + "5,5,5,\n",
+      "DELETE FROM root.vehicle.d0.s0,root.vehicle.d1.s1 WHERE time < 3",
+      "SELECT * FROM root.vehicle.*",
+      "5,5,5,\n",
+      "DELETE FROM root.vehicle.** WHERE time < 7",
+      "SELECT * FROM root.vehicle.*",
+      "",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void selectTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,101)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,102)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,103)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,105)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,106)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,107)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,108)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,109)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,110)",
+      "SELECT * FROM root.vehicle.d0 WHERE s0 < 104",
+      "1,101,\n" + "2,102,\n" + "3,103,\n",
+      "SELECT * FROM root.vehicle.d0 WHERE s0 > 105 and time < 8",
+      "6,106,\n" + "7,107,\n",
+      "SELECT * FROM root.vehicle.d0",
+      "1,101,\n"
+          + "2,102,\n"
+          + "3,103,\n"
+          + "4,104,\n"
+          + "5,105,\n"
+          + "6,106,\n"
+          + "7,107,\n"
+          + "8,108,\n"
+          + "9,109,\n"
+          + "10,110,\n",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void funcTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
+      "SELECT COUNT(s0) FROM root.vehicle.d0",
+      "0,10,\n",
+      "SELECT COUNT(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 105",
+      "0,4,\n",
+      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
+      "0,10,\n",
+      "SELECT MAX_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 > 105",
+      "0,5,\n",
+      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
+      "0,1,\n",
+      "SELECT MIN_TIME(s0) FROM root.vehicle.d0 WHERE root.vehicle.d0.s0 < 106",
+      "0,6,\n",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
+      "0,110,\n",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
+      "0,106,\n",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
+      "0,101,\n",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
+      "0,107,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
+      "SELECT * FROM root.vehicle.d0",
+      "NOW(),5,\n",
+      "UPDATE root.vehicle.d0 SET s0 = 10 WHERE time <= NOW()",
+      "SELECT * FROM root.vehicle.d0",
+      "NOW(),10,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
+      "SELECT * FROM root.vehicle.d0",
+      "",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void funcTestWithOutTimeGenerator() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
+      "SELECT COUNT(s0) FROM root.vehicle.d0",
+      "0,10,\n",
+      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
+      "0,10,\n",
+      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
+      "0,1,\n",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
+      "0,110,\n",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
+      "0,106,\n",
+      "SELECT SUM(s0) FROM root.vehicle.d0 WHERE time > 4",
+      "0,621.0,\n",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
+      "0,101,\n",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
+      "0,107,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time <= 10",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(NOW(),5)",
+      "SELECT * FROM root.vehicle.d0",
+      "NOW(),5,\n",
+      "DELETE FROM root.vehicle.d0.s0 WHERE time <= NOW()",
+      "SELECT * FROM root.vehicle.d0",
+      "",
+      "SELECT COUNT(s0) FROM root.vehicle.d0",
+      "0,0,\n",
+      "SELECT MAX_TIME(s0) FROM root.vehicle.d0",
+      "",
+      "SELECT MIN_TIME(s0) FROM root.vehicle.d0",
+      "",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0",
+      "",
+      "SELECT MAX_VALUE(s0) FROM root.vehicle.d0 WHERE time > 4",
+      "",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0",
+      "",
+      "SELECT MIN_VALUE(s0) FROM root.vehicle.d0 WHERE time < 5",
+      "",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  public void groupByTest() {
+    String[] sqlS = {
+      "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(1,110)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(2,109)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(3,108)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(4,107)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(5,106)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(6,105)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(7,104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(8,103)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(9,102)",
+      "INSERT INTO root.vehicle.d0(timestamp,s0) values(10,101)",
+      "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(1,101)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(2,102)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(3,103)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(4,104)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(5,105)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(6,106)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(7,107)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(8,108)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(9,109)",
+      "INSERT INTO root.vehicle.d0(timestamp,s1) values(10,110)",
+      "SELECT COUNT(s0), COUNT(s1) FROM root.vehicle.d0 WHERE s1 < 109 GROUP BY(4ms,[1,10])",
+      "1,3,3,\n" + "4,4,4,\n" + "8,1,1,\n",
+      "SELECT COUNT(s0), MAX_VALUE(s1) FROM root.vehicle.d0 WHERE time < 7 GROUP BY(3ms,2,[1,5])",
+      "1,1,101,\n" + "2,3,104,\n" + "5,1,105,\n",
+      "SELECT MIN_VALUE(s0), MAX_TIME(s1) FROM root.vehicle.d0 WHERE s1 > 102 and time < 9 GROUP BY(3ms,1,[1,4],[6,9])",
+      "1,108,3,\n" + "4,105,6,\n" + "7,103,8,\n",
+      "DELETE TIMESERIES root.vehicle.**"
+    };
+    executeSQL(sqlS);
+  }
+
+  private void executeSQL(String[] sqls) {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String result = "";
+      Long now_start = 0L;
+      boolean cmp = false;
+
+      for (String sql : sqls) {
+        if (cmp) {
+          Assert.assertEquals(sql, result);
+          cmp = false;
+        } else if (sql.equals("SHOW TIMESERIES")) {
+          DatabaseMetaData data = connection.getMetaData();
+          result = data.toString();
+          cmp = true;
+        } else {
+          if (sql.contains("NOW()") && now_start == 0L) {
+            now_start = System.currentTimeMillis();
+          }
+
+          if (sql.split(" ")[0].equals("SELECT")) {
+            ResultSet resultSet = statement.executeQuery(sql);
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            int count = metaData.getColumnCount();
+            String[] column = new String[count];
+            for (int i = 0; i < count; i++) {
+              column[i] = metaData.getColumnName(i + 1);
+            }
+            result = "";
+            while (resultSet.next()) {
+              for (int i = 1; i <= count; i++) {
+                if (now_start > 0L && column[i - 1].equals(TestConstant.TIMESTAMP_STR)) {
+                  String timestr = resultSet.getString(i);
+                  Long tn = Long.valueOf(timestr);
+                  Long now = System.currentTimeMillis();
+                  if (tn >= now_start && tn <= now) {
+                    timestr = "NOW()";
+                  }
+                  result += timestr + ',';
+                } else {
+                  result += resultSet.getString(i) + ',';
+                }
+              }
+              result += '\n';
+            }
+            cmp = true;
+          }
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBDeletionIT.java
similarity index 86%
copy from integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java
copy to integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBDeletionIT.java
index a05c920524..a8696a29e2 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBDeletionIT.java
@@ -17,19 +17,20 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.integration;
+package org.apache.iotdb.db.it;
 
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.integration.env.ConfigFactory;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.ClusterTest;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -41,7 +42,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
-@Category({LocalStandaloneTest.class})
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBDeletionIT {
 
   private static String[] creationSqls =
@@ -59,12 +61,16 @@ public class IoTDBDeletionIT {
       "INSERT INTO root.vehicle.d0(timestamp,s0,s1,s2,s3,s4" + ") VALUES(%d,%d,%d,%f,%s,%b)";
   private String deleteAllTemplate = "DELETE FROM root.vehicle.d0 WHERE time <= 10000";
   private long prevPartitionInterval;
+  private long size;
 
   @Before
   public void setUp() throws Exception {
     Locale.setDefault(Locale.ENGLISH);
-    prevPartitionInterval = IoTDBDescriptor.getInstance().getConfig().getPartitionInterval();
+    prevPartitionInterval = ConfigFactory.getConfig().getPartitionInterval();
     ConfigFactory.getConfig().setPartitionInterval(1000);
+    size = ConfigFactory.getConfig().getMemtableSizeThreshold();
+    // Adjust memstable threshold size to make it flush automatically
+    ConfigFactory.getConfig().setMemtableSizeThreshold(10000);
     EnvFactory.getEnv().initBeforeTest();
     prepareSeries();
   }
@@ -73,6 +79,7 @@ public class IoTDBDeletionIT {
   public void tearDown() throws Exception {
     EnvFactory.getEnv().cleanAfterTest();
     ConfigFactory.getConfig().setPartitionInterval(prevPartitionInterval);
+    ConfigFactory.getConfig().setMemtableSizeThreshold(size);
   }
 
   /**
@@ -81,7 +88,6 @@ public class IoTDBDeletionIT {
    * @throws SQLException
    */
   @Test
-  @Category({ClusterTest.class})
   public void testUnsupportedValueFilter() throws SQLException {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -91,21 +97,7 @@ public class IoTDBDeletionIT {
       statement.execute("insert into root.vehicle.d0(time,s4) values (10,true)");
 
       String errorMsg =
-          "303: Check metadata error: For delete statement, where clause can only"
-              + " contain time expressions, value filter is not currently supported.";
-
-      String errorMsg2 =
-          "303: Check metadata error: For delete statement, where clause can only contain"
-              + " atomic expressions like : time > XXX, time <= XXX,"
-              + " or two atomic expressions connected by 'AND'";
-
-      try {
-        statement.execute(
-            "DELETE FROM root.vehicle.d0.s0  WHERE s0 <= 300 AND time > 0 AND time < 100");
-        fail("should not reach here!");
-      } catch (SQLException e) {
-        assertEquals(errorMsg2, e.getMessage());
-      }
+          "416: For delete statement, where clause can only contain time expressions, value filter is not currently supported.";
 
       try {
         statement.execute("DELETE FROM root.vehicle.d0.s0  WHERE s0 <= 300 AND s0 > 0");
@@ -155,7 +147,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void test() throws SQLException {
     prepareData();
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -195,13 +186,12 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testMerge() throws SQLException {
     prepareMerge();
 
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
-      statement.execute("merge");
+      //      statement.execute("merge");
       statement.execute("DELETE FROM root.vehicle.d0.** WHERE time <= 15000");
 
       // before merge completes
@@ -226,7 +216,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testDelAfterFlush() throws SQLException {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -248,7 +237,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testRangeDelete() throws SQLException {
     prepareData();
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -285,7 +273,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testFullDeleteWithoutWhereClause() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -305,7 +292,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testPartialPathRangeDelete() throws SQLException {
     prepareData();
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -334,9 +320,6 @@ public class IoTDBDeletionIT {
 
   @Test
   public void testDelFlushingMemtable() throws SQLException {
-    long size = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    // Adjust memstable threshold size to make it flush automatically
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(10000);
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
 
@@ -355,44 +338,39 @@ public class IoTDBDeletionIT {
       }
       cleanData();
     }
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(size);
   }
 
   @Test
   public void testDelMultipleFlushingMemtable() throws SQLException {
-    long size = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    // Adjust memstable threshold size to make it flush automatically
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(1000000);
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
 
-      for (int i = 1; i <= 100000; i++) {
-        statement.addBatch(
+      // todo improve to executeBatch
+      for (int i = 1; i <= 1000; i++) {
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
 
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 15000 and time <= 30000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 30000 and time <= 40000");
-      for (int i = 100001; i <= 200000; i++) {
-        statement.addBatch(
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 150 and time <= 300");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 300 and time <= 400");
+      // todo improve to executeBatch
+      for (int i = 1001; i <= 2000; i++) {
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 50000 and time <= 80000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 90000 and time <= 110000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 150000 and time <= 165000");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 500 and time <= 800");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 900 and time <= 1100");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 1500 and time <= 1650");
       statement.execute("flush");
       try (ResultSet set = statement.executeQuery("SELECT s0 FROM root.vehicle.d0")) {
         int cnt = 0;
         while (set.next()) {
           cnt++;
         }
-        assertEquals(110000, cnt);
+        assertEquals(1100, cnt);
       }
       cleanData();
     }
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(size);
   }
 
   @Test
@@ -423,7 +401,6 @@ public class IoTDBDeletionIT {
   }
 
   @Test
-  @Category({ClusterTest.class})
   public void testDelSeriesWithSpecialSymbol() throws SQLException {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -483,13 +460,13 @@ public class IoTDBDeletionIT {
         statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.execute("merge");
+      //      statement.execute("merge");
       // prepare Unseq-File
       for (int i = 1; i <= 100; i++) {
         statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.execute("merge");
+      //      statement.execute("merge");
       // prepare BufferWrite cache
       for (int i = 301; i <= 400; i++) {
         statement.execute(
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBMultiDeviceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBMultiDeviceIT.java
new file mode 100644
index 0000000000..cbe085cef8
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBMultiDeviceIT.java
@@ -0,0 +1,297 @@
+/*
+ * 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.it;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+import org.apache.iotdb.itbase.env.BaseConfig;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBMultiDeviceIT {
+
+  private static BaseConfig tsFileConfig = ConfigFactory.getConfig();
+  private static int maxNumberOfPointsInPage;
+  private static int pageSizeInByte;
+  private static int groupSizeInByte;
+  private static long prevPartitionInterval;
+
+  @Before
+  public void setUp() throws Exception {
+    // use small page setting
+    // origin value
+    maxNumberOfPointsInPage = tsFileConfig.getMaxNumberOfPointsInPage();
+    pageSizeInByte = tsFileConfig.getPageSizeInByte();
+    groupSizeInByte = tsFileConfig.getGroupSizeInByte();
+
+    // new value
+    tsFileConfig.setMaxNumberOfPointsInPage(1000);
+    tsFileConfig.setPageSizeInByte(1024 * 150);
+    tsFileConfig.setGroupSizeInByte(1024 * 1000);
+    ConfigFactory.getConfig().setMemtableSizeThreshold(1024 * 1000);
+    prevPartitionInterval = ConfigFactory.getConfig().getPartitionInterval();
+    ConfigFactory.getConfig().setPartitionInterval(100);
+    ConfigFactory.getConfig().setCompressor("LZ4");
+
+    EnvFactory.getEnv().initBeforeTest();
+
+    insertData();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    // recovery value
+    ConfigFactory.getConfig().setMaxNumberOfPointsInPage(maxNumberOfPointsInPage);
+    ConfigFactory.getConfig().setPageSizeInByte(pageSizeInByte);
+    ConfigFactory.getConfig().setGroupSizeInByte(groupSizeInByte);
+
+    EnvFactory.getEnv().cleanAfterTest();
+
+    ConfigFactory.getConfig().setPartitionInterval(prevPartitionInterval);
+    ConfigFactory.getConfig().setMemtableSizeThreshold(groupSizeInByte);
+    ConfigFactory.getConfig().setCompressor("SNAPPY");
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : TestConstant.createSql) {
+        statement.execute(sql);
+      }
+
+      statement.execute("SET STORAGE GROUP TO root.fans");
+      statement.execute("CREATE TIMESERIES root.fans.d0.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.fans.d1.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.fans.d2.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.fans.d3.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.car.d0.s1 WITH DATATYPE=INT64, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.car.d1.s1 WITH DATATYPE=INT64, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.car.d2.s1 WITH DATATYPE=INT64, ENCODING=RLE");
+
+      // insert of data time range :0-1000 into fans
+      // todo improve to executeBatch
+      for (int time = 0; time < 1000; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d2(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d3(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d2(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+      }
+
+      // insert large amount of data time range : 13700 ~ 24000
+      // todo improve to executeBatch
+      for (int time = 13700; time < 24000; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d2(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d3(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d2(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+      }
+
+      // insert large amount of data time range : 3000 ~ 13600
+      // todo improve to executeBatch
+      for (int time = 3000; time < 13600; time++) {
+        // System.out.println("===" + time);
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d2(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d3(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d2(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+      }
+
+      statement.execute("flush");
+      //      statement.execute("merge");
+
+      // unsequential data, memory data
+      // todo improve to executeBatch
+      for (int time = 10000; time < 11000; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d2(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d3(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d2(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+      }
+
+      // sequential data, memory data
+      // todo improve to executeBatch
+      for (int time = 200000; time < 201000; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d2(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql =
+            String.format("insert into root.fans.d3(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d0(timestamp,s0) values(%s,%s)", time, time % 70);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d1(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+        sql = String.format("insert into root.car.d2(timestamp,s0) values(%s,%s)", time, time % 40);
+        statement.execute(sql);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testMultiDeviceQueryAndDelete() {
+    testSelectAll();
+    testSelectAfterDelete();
+  }
+
+  private void testSelectAll() {
+    String selectSql = "select * from root.**";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        long before = -1;
+        while (resultSet.next()) {
+          long cur = Long.parseLong(resultSet.getString(TestConstant.TIMESTAMP_STR));
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          before = cur;
+          cnt++;
+        }
+        assertEquals(22900, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private void testSelectAfterDelete() {
+    String selectSql = "select * from root.**";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("DELETE FROM root.fans.** WHERE time <= 1000");
+      statement.execute("DELETE FROM root.car.** WHERE time <= 1000");
+      statement.execute("DELETE FROM root.fans.** WHERE time >= 200500 and time < 201000");
+      statement.execute("DELETE FROM root.car.** WHERE time >= 200500 and time < 201000");
+
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        long before = -1;
+        while (resultSet.next()) {
+          long cur = Long.parseLong(resultSet.getString(TestConstant.TIMESTAMP_STR));
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          before = cur;
+          cnt++;
+        }
+        assertEquals(21400, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSameMeasurementsDifferentTypesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSameMeasurementsDifferentTypesIT.java
new file mode 100644
index 0000000000..83e9ae6cc8
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSameMeasurementsDifferentTypesIT.java
@@ -0,0 +1,180 @@
+/*
+ * 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.it;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+import org.apache.iotdb.itbase.env.BaseConfig;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBSameMeasurementsDifferentTypesIT {
+
+  private static BaseConfig tsFileConfig = ConfigFactory.getConfig();
+  private static int maxNumberOfPointsInPage;
+  private static int pageSizeInByte;
+  private static int groupSizeInByte;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+
+    // use small page setting
+    // origin value
+    maxNumberOfPointsInPage = tsFileConfig.getMaxNumberOfPointsInPage();
+    pageSizeInByte = tsFileConfig.getPageSizeInByte();
+    groupSizeInByte = tsFileConfig.getGroupSizeInByte();
+
+    // new value
+    ConfigFactory.getConfig()
+        .setMaxNumberOfPointsInPage(1000)
+        .setPageSizeInByte(1024 * 150)
+        .setGroupSizeInByte(1024 * 1000)
+        .setMemtableSizeThreshold(1024 * 1000);
+
+    EnvFactory.getEnv().initBeforeClass();
+
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    // recovery value
+    ConfigFactory.getConfig()
+        .setMaxNumberOfPointsInPage(maxNumberOfPointsInPage)
+        .setPageSizeInByte(pageSizeInByte)
+        .setGroupSizeInByte(groupSizeInByte)
+        .setMemtableSizeThreshold(groupSizeInByte);
+    EnvFactory.getEnv().cleanAfterClass();
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : TestConstant.createSql) {
+        statement.execute(sql);
+      }
+
+      statement.execute("SET STORAGE GROUP TO root.fans");
+      statement.execute("CREATE TIMESERIES root.fans.d0.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.fans.d1.s0 WITH DATATYPE=INT64, ENCODING=RLE");
+
+      for (int time = 1; time < 10; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 10);
+        statement.execute(sql);
+        sql = String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 5);
+        statement.execute(sql);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectAllTest() {
+    String[] retArray =
+        new String[] {
+          "1,1,1", "2,2,2", "3,3,3", "4,4,4", "5,5,0", "6,6,1", "7,7,2", "8,8,3", "9,9,4"
+        };
+
+    String selectSql = "select * from root.**";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement1 = connection.createStatement();
+        Statement statement2 = connection.createStatement()) {
+      statement1.setFetchSize(10);
+      ResultSet resultSet1 = statement1.executeQuery(selectSql);
+      int cnt1 = 0;
+      while (resultSet1.next() && cnt1 < 5) {
+        StringBuilder builder = new StringBuilder();
+        builder
+            .append(resultSet1.getString(TestConstant.TIMESTAMP_STR))
+            .append(",")
+            .append(resultSet1.getString("root.fans.d0.s0"))
+            .append(",")
+            .append(resultSet1.getString("root.fans.d1.s0"));
+        Assert.assertEquals(retArray[cnt1], builder.toString());
+        cnt1++;
+      }
+
+      statement2.setFetchSize(10);
+      ResultSet resultSet2 = statement2.executeQuery(selectSql);
+      int cnt2 = 0;
+      while (resultSet2.next()) {
+        StringBuilder builder = new StringBuilder();
+        builder
+            .append(resultSet2.getString(TestConstant.TIMESTAMP_STR))
+            .append(",")
+            .append(resultSet2.getString("root.fans.d0.s0"))
+            .append(",")
+            .append(resultSet2.getString("root.fans.d1.s0"));
+        Assert.assertEquals(retArray[cnt2], builder.toString());
+        cnt2++;
+      }
+      Assert.assertEquals(9, cnt2);
+
+      // use do-while instead of while because in the previous while loop, we have executed the next
+      // function,
+      // and the cursor has been moved to the next position, so we should fetch that value first.
+      do {
+        StringBuilder builder = new StringBuilder();
+        builder
+            .append(resultSet1.getString(TestConstant.TIMESTAMP_STR))
+            .append(",")
+            .append(resultSet1.getString("root.fans.d0.s0"))
+            .append(",")
+            .append(resultSet1.getString("root.fans.d1.s0"));
+        Assert.assertEquals(retArray[cnt1], builder.toString());
+        cnt1++;
+      } while (resultSet1.next());
+      // Although the statement2 has the same sql as statement1, they shouldn't affect each other.
+      // So the statement1's ResultSet should also have 9 rows in total.
+      Assert.assertEquals(9, cnt1);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java
new file mode 100644
index 0000000000..f42f4d7f44
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java
@@ -0,0 +1,1133 @@
+/*
+ * 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.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBSimpleQueryIT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void testCreateTimeseries1() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      try (ResultSet resultSet = statement.executeQuery("show timeseries root.sg1.d0.s1")) {
+        if (resultSet.next()) {
+          assertEquals("PLAIN", resultSet.getString("encoding").toUpperCase());
+        }
+      }
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testFailedToCreateTimeseriesSDTProperties() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      try {
+        statement.execute(
+            "CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN,'LOSS'='SDT','COMPDEV'='-2'");
+        fail();
+      } catch (Exception e) {
+        assertEquals(
+            "318: SDT compression deviation cannot be negative. Failed to create timeseries for path root.sg1.d0.s1",
+            e.getMessage());
+      }
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+      assertEquals(0, count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testLastQueryNonCached() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "create timeseries root.turbine.d1.s1 with datatype=FLOAT, encoding=GORILLA, compression=SNAPPY");
+      statement.execute(
+          "create timeseries root.turbine.d1.s2 with datatype=FLOAT, encoding=GORILLA, compression=SNAPPY");
+      statement.execute(
+          "create timeseries root.turbine.d2.s1 with datatype=FLOAT, encoding=GORILLA, compression=SNAPPY");
+      statement.execute("insert into root.turbine.d1(timestamp,s1,s2) values(1,1,2)");
+
+      String[] results = {"root.turbine.d1.s1", "root.turbine.d1.s2"};
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("select last ** from root")) {
+        while (resultSet.next()) {
+          String path = resultSet.getString("timeseries");
+          assertEquals(results[count], path);
+          count++;
+        }
+      }
+
+      assertEquals(2, count);
+
+      try (ResultSet resultSet = statement.executeQuery("select last * from root")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingSeq() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=DOUBLE,ENCODING=PLAIN,LOSS=SDT,COMPDEV=0.01");
+
+      int degree = 0;
+      for (int time = 0; time < 100; time++) {
+        // generate data in sine wave pattern
+        double value = 10 * Math.sin(degree++ * 3.141592653589793D / 180.0D);
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + "," + value + ")";
+        statement.execute(sql);
+      }
+
+      // before SDT encoding
+      ResultSet resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      int count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(count, 100);
+
+      // after flush and SDT encoding
+      statement.execute("flush");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(15, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingCompDev() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN,LOSS=SDT,COMPDEV=2");
+
+      for (int time = 1; time < 8; time++) {
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + ",1)";
+        statement.execute(sql);
+      }
+      statement.execute("flush");
+
+      String sql = "insert into root.sg1.d0(timestamp,s0) values(15,10)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(16,20)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(17,1)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(18,30)";
+      statement.execute(sql);
+      statement.execute("flush");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.**");
+      int count = 0;
+
+      String[] timestamps = {"1", "7", "15", "16", "17", "18"};
+      String[] values = {"1", "1", "10", "20", "1", "30"};
+
+      while (resultSet.next()) {
+        assertEquals(timestamps[count], resultSet.getString("Time"));
+        assertEquals(values[count], resultSet.getString("root.sg1.d0.s0"));
+        count++;
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingCompMin() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN,LOSS=SDT,COMPDEV=2, COMPMINTIME=1");
+
+      for (int time = 1; time < 8; time++) {
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + ",1)";
+        statement.execute(sql);
+      }
+      statement.execute("flush");
+
+      String sql = "insert into root.sg1.d0(timestamp,s0) values(15,10)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(16,20)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(17,1)";
+      statement.execute(sql);
+      sql = "insert into root.sg1.d0(timestamp,s0) values(18,30)";
+      statement.execute(sql);
+      statement.execute("flush");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.**");
+      int count = 0;
+
+      // will not store time = 16 since time distance to last stored time 15 is within compMinTime
+      String[] timestamps = {"1", "7", "15", "17", "18"};
+      String[] values = {"1", "1", "10", "1", "30"};
+
+      while (resultSet.next()) {
+        assertEquals(timestamps[count], resultSet.getString("Time"));
+        assertEquals(values[count], resultSet.getString("root.sg1.d0.s0"));
+        count++;
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingCompMax() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN,LOSS=SDT,COMPDEV=2, COMPMAXTIME=20");
+
+      for (int time = 1; time < 50; time++) {
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + ",1)";
+        statement.execute(sql);
+      }
+      statement.execute("flush");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.**");
+      int count = 0;
+
+      String[] timestamps = {"1", "21", "41", "49"};
+      String[] values = {"1", "1", "1", "1"};
+
+      while (resultSet.next()) {
+        assertEquals(timestamps[count], resultSet.getString("Time"));
+        assertEquals(values[count], resultSet.getString("root.sg1.d0.s0"));
+        count++;
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingUnseq() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=DOUBLE,ENCODING=PLAIN,LOSS=SDT,COMPDEV=0.01");
+
+      int degree = 0;
+      for (int time = 0; time < 100; time++) {
+        // generate data in sine wave pattern
+        double value = 10 * Math.sin(degree++ * 3.141592653589793D / 180.0D);
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + "," + value + ")";
+        statement.execute(sql);
+      }
+
+      // insert unseq
+      String sql = "insert into root.sg1.d0(timestamp,s0) values(2,19)";
+      statement.execute(sql);
+
+      // before SDT encoding
+      ResultSet resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      int count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(count, 100);
+
+      // after flush and SDT encoding
+      statement.execute("flush");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(18, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingMergeSeq() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=DOUBLE,ENCODING=PLAIN,LOSS=SDT,COMPDEV=0.01");
+
+      int degree = 0;
+      for (int time = 0; time < 100; time++) {
+        // generate data in sine wave pattern
+        double value = 10 * Math.sin(degree++ * 3.141592653589793D / 180.0D);
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + "," + value + ")";
+        statement.execute(sql);
+      }
+
+      // before SDT encoding
+      ResultSet resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      int count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(100, count);
+
+      // after flush and SDT encoding
+      statement.execute("flush");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(15, count);
+
+      // no sdt encoding when merging
+      //      statement.execute("merge");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(15, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testSDTEncodingMergeUnseq() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      // test set sdt property
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=DOUBLE,ENCODING=PLAIN,LOSS=SDT,COMPDEV=0.01");
+
+      int degree = 0;
+      for (int time = 0; time < 100; time++) {
+        // generate data in sine wave pattern
+        double value = 10 * Math.sin(degree++ * 3.141592653589793D / 180.0D);
+        String sql = "insert into root.sg1.d0(timestamp,s0) values(" + time + "," + value + ")";
+        statement.execute(sql);
+      }
+
+      // insert unseq
+      String sql = "insert into root.sg1.d0(timestamp,s0) values(2,19)";
+      statement.execute(sql);
+
+      // before SDT encoding
+      ResultSet resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      int count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(100, count);
+
+      // after flush and SDT encoding
+      statement.execute("flush");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(18, count);
+
+      // no sdt encoding when merging
+      //      statement.execute("merge");
+      resultSet = statement.executeQuery("select s0 from root.sg1.d0");
+      count = 0;
+      while (resultSet.next()) {
+        count++;
+      }
+      assertEquals(18, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Ignore
+  @Test
+  public void testEmptyDataSet() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      ResultSet resultSet = statement.executeQuery("select * from root.**");
+      // has an empty time column
+      Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+      try {
+        while (resultSet.next()) {
+          fail();
+        }
+
+        resultSet =
+            statement.executeQuery(
+                "select count(*) from root where time >= 1 and time <= 100 group by ([0, 100), 20ms, 20ms)");
+        // has an empty time column
+        Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          fail();
+        }
+
+        resultSet = statement.executeQuery("select count(*) from root");
+        // has no column
+        Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          fail();
+        }
+
+        resultSet = statement.executeQuery("select * from root.** align by device");
+        // has time and device columns
+        Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          fail();
+        }
+
+        resultSet = statement.executeQuery("select count(*) from root align by device");
+        // has device column
+        Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          fail();
+        }
+
+        resultSet =
+            statement.executeQuery(
+                "select count(*) from root where time >= 1 and time <= 100 "
+                    + "group by ([0, 100), 20ms, 20ms) align by device");
+        // has time and device columns
+        Assert.assertEquals(1, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          fail();
+        }
+      } finally {
+        resultSet.close();
+      }
+
+      resultSet.close();
+    }
+  }
+
+  @Test
+  public void testOrderByTimeDesc() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (1, 1)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (2, 2)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (3, 3)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (4, 4)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s1) VALUES (3, 3)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s1) VALUES (1, 1)");
+      statement.execute("flush");
+
+      String[] ret =
+          new String[] {
+            "4,4,null", "3,3,3", "2,2,null", "1,1,1",
+          };
+
+      int cur = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery("select * from root.** order by time desc")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("Time")
+                  + ","
+                  + resultSet.getString("root.sg1.d0.s0")
+                  + ","
+                  + resultSet.getString("root.sg1.d0.s1");
+          assertEquals(ret[cur], ans);
+          cur++;
+        }
+      }
+    }
+  }
+
+  @Test
+  public void testShowTimeseriesDataSet1() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s2 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s3 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s4 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s5 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s6 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s7 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s8 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s9 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s10 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      statement.execute("flush");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(10, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testShowTimeseriesDataSet2() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(10);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s2 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s3 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s4 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s5 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s6 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s7 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s8 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s9 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s10 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      statement.execute("flush");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(10, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testShowTimeseriesDataSet3() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(15);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s2 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s3 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s4 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s5 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s6 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s7 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s8 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s9 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s10 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      statement.execute("flush");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(10, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testShowTimeseriesDataSet4() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s2 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s3 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s4 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s5 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s6 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s7 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s8 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s9 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s10 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      statement.execute("flush");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries limit 8")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(8, count);
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void testShowTimeseriesWithLimitOffset() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      List<String> exps =
+          Arrays.asList("root.sg1.d0.s1", "root.sg1.d0.s2", "root.sg1.d0.s3", "root.sg1.d0.s4");
+
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s1) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s2) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s3) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s4) VALUES (5, 5)");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries limit 2 offset 1")) {
+        while (resultSet.next()) {
+          Assert.assertTrue(exps.contains(resultSet.getString(1)));
+          ++count;
+        }
+      }
+      Assert.assertEquals(2, count);
+    }
+  }
+
+  @Test
+  public void testShowDevicesWithLimitOffset() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      List<String> exps = Arrays.asList("root.sg1.d1,false", "root.sg1.d2,false");
+
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s1) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d1(timestamp, s2) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d2(timestamp, s3) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d3(timestamp, s4) VALUES (5, 5)");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show devices limit 2 offset 1")) {
+        while (resultSet.next()) {
+          Assert.assertEquals(
+              exps.get(count), resultSet.getString(1) + "," + resultSet.getString(2));
+          ++count;
+        }
+      }
+      Assert.assertEquals(2, count);
+    }
+  }
+
+  @Test
+  public void testShowDevicesWithLimit() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      List<String> exps = Arrays.asList("root.sg1.d0,false", "root.sg1.d1,false");
+
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s1) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d1(timestamp, s2) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d2(timestamp, s3) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d3(timestamp, s4) VALUES (5, 5)");
+
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show devices limit 2")) {
+        while (resultSet.next()) {
+          Assert.assertEquals(
+              exps.get(count), resultSet.getString(1) + "," + resultSet.getString(2));
+          ++count;
+        }
+      }
+      Assert.assertEquals(2, count);
+    }
+  }
+
+  @Test
+  public void testFirstOverlappedPageFiltered() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      // seq chunk : [1,10]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (1, 1)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (10, 10)");
+
+      statement.execute("flush");
+
+      // seq chunk : [13,20]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (13, 13)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (20, 20)");
+
+      statement.execute("flush");
+
+      // unseq chunk : [5,15]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (15, 15)");
+
+      statement.execute("flush");
+
+      long count = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery("select s0 from root.sg1.d0 where s0 > 18")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(1, count);
+    }
+  }
+
+  @Test
+  public void testPartialInsertion() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      try {
+        statement.execute("INSERT INTO root.sg1.d0(timestamp, s0, s1) VALUES (1, 1, 2.2)");
+        fail();
+      } catch (SQLException e) {
+        assertTrue(e.getMessage().contains("s1"));
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select s0, s1 from root.sg1.d0")) {
+        while (resultSet.next()) {
+          assertEquals(1, resultSet.getInt("root.sg1.d0.s0"));
+          assertEquals(null, resultSet.getString("root.sg1.d0.s1"));
+        }
+      }
+    }
+  }
+
+  @Test
+  public void testOverlappedPagesMerge() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      // seq chunk : start-end [1000, 1000]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (1000, 0)");
+
+      statement.execute("flush");
+
+      // unseq chunk : [1,10]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (1, 1)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (10, 10)");
+
+      statement.execute("flush");
+
+      // usneq chunk : [5,15]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (5, 5)");
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (15, 15)");
+
+      statement.execute("flush");
+
+      // unseq chunk : [15,15]
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (15, 150)");
+
+      statement.execute("flush");
+
+      long count = 0;
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select s0 from root.sg1.d0 where s0 < 100")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      Assert.assertEquals(4, count);
+    }
+  }
+
+  @Test
+  public void testUnseqUnsealedDeleteQuery() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute("CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT32,ENCODING=PLAIN");
+
+      // seq data
+      statement.execute("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (1000, 1)");
+      statement.execute("flush");
+
+      for (int i = 1; i <= 10; i++) {
+        statement.execute(
+            String.format("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (%d, %d)", i, i));
+      }
+
+      statement.execute("flush");
+
+      // unseq data
+      for (int i = 11; i <= 20; i++) {
+        statement.execute(
+            String.format("INSERT INTO root.sg1.d0(timestamp, s0) VALUES (%d, %d)", i, i));
+      }
+
+      statement.execute("delete from root.sg1.d0.s0 where time <= 15");
+
+      long count = 0;
+
+      try (ResultSet resultSet = statement.executeQuery("select * from root.**")) {
+        while (resultSet.next()) {
+          count++;
+        }
+      }
+
+      System.out.println(count);
+    }
+  }
+
+  @Test
+  public void testTimeseriesMetadataCache() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      for (int i = 0; i < 10000; i++) {
+        statement.execute(
+            "CREATE TIMESERIES root.sg1.d0.s" + i + " WITH DATATYPE=INT32,ENCODING=PLAIN");
+      }
+      for (int i = 1; i < 10000; i++) {
+        statement.execute("INSERT INTO root.sg1.d0(timestamp, s" + i + ") VALUES (1000, 1)");
+      }
+      statement.execute("flush");
+      statement.executeQuery("select s0 from root.sg1.d0");
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testInvalidSchema() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      try {
+        statement.execute(
+            "CREATE TIMESERIES root.sg1.d1.s1 with datatype=BOOLEAN, encoding=TS_2DIFF");
+        fail();
+      } catch (Exception e) {
+        Assert.assertEquals("303: encoding TS_2DIFF does not support BOOLEAN", e.getMessage());
+      }
+
+      try {
+        statement.execute(
+            "CREATE TIMESERIES root.sg1.d1.s3 with datatype=DOUBLE, encoding=REGULAR");
+        fail();
+      } catch (Exception e) {
+        Assert.assertEquals("303: encoding REGULAR does not support DOUBLE", e.getMessage());
+      }
+
+      try {
+        statement.execute("CREATE TIMESERIES root.sg1.d1.s4 with datatype=TEXT, encoding=TS_2DIFF");
+        fail();
+      } catch (Exception e) {
+        Assert.assertEquals("303: encoding TS_2DIFF does not support TEXT", e.getMessage());
+      }
+
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testUseSameStatement() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s0 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d0.s1 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s0 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s1 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
+
+      statement.execute("insert into root.sg1.d0(timestamp,s0,s1) values(1,1,1)");
+      statement.execute("insert into root.sg1.d1(timestamp,s0,s1) values(1000,1000,1000)");
+      statement.execute("insert into root.sg1.d0(timestamp,s0,s1) values(10,10,10)");
+
+      List<ResultSet> resultSetList = new ArrayList<>();
+
+      ResultSet r1 = statement.executeQuery("select * from root.sg1.d0 where time <= 1");
+      resultSetList.add(r1);
+
+      ResultSet r2 = statement.executeQuery("select * from root.sg1.d1 where s0 == 1000");
+      resultSetList.add(r2);
+
+      ResultSet r3 = statement.executeQuery("select * from root.sg1.d0 where s1 == 10");
+      resultSetList.add(r3);
+
+      r1.next();
+      Assert.assertEquals(r1.getLong(1), 1L);
+      Assert.assertEquals(r1.getLong(2), 1L);
+      Assert.assertEquals(r1.getLong(3), 1L);
+
+      r2.next();
+      Assert.assertEquals(r2.getLong(1), 1000L);
+      Assert.assertEquals(r2.getLong(2), 1000L);
+      Assert.assertEquals(r2.getLong(3), 1000L);
+
+      r3.next();
+      Assert.assertEquals(r3.getLong(1), 10L);
+      Assert.assertEquals(r3.getLong(2), 10L);
+      Assert.assertEquals(r3.getLong(3), 10L);
+    }
+  }
+
+  @Test
+  public void testInvalidMaxPointNumber() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s1 with datatype=FLOAT, encoding=TS_2DIFF, "
+              + "'max_point_number'='4'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s2 with datatype=FLOAT, encoding=TS_2DIFF, "
+              + "'max_point_number'='2.5'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s3 with datatype=FLOAT, encoding=RLE, "
+              + "'max_point_number'='q'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s4 with datatype=FLOAT, encoding=RLE, "
+              + "'max_point_number'='-1'");
+      statement.execute(
+          "insert into root.sg1.d1(timestamp,s1,s2,s3,s4) values(1,1.1234,1.1234,1.1234,1.1234)");
+
+      try (ResultSet r1 = statement.executeQuery("select s1 from root.sg1.d1")) {
+        r1.next();
+        Assert.assertEquals(1.1234f, r1.getFloat(2), 0);
+      }
+
+      try (ResultSet r2 = statement.executeQuery("select s3 from root.sg1.d1")) {
+        r2.next();
+        Assert.assertEquals(1.12f, r2.getFloat(2), 0);
+      }
+
+      try (ResultSet r3 = statement.executeQuery("select s3 from root.sg1.d1")) {
+        r3.next();
+        Assert.assertEquals(1.12f, r3.getFloat(2), 0);
+      }
+
+      try (ResultSet r4 = statement.executeQuery("select s4 from root.sg1.d1")) {
+        r4.next();
+        Assert.assertEquals(1.12f, r4.getFloat(2), 0);
+      }
+
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testStorageGroupWithHyphenInName() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.execute("SET STORAGE GROUP TO root.group_with_hyphen");
+    } catch (SQLException e) {
+      fail();
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try (ResultSet resultSet = statement.executeQuery("SHOW STORAGE GROUP")) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          builder.append(resultSet.getString(1));
+          Assert.assertEquals(builder.toString(), "root.group_with_hyphen");
+        }
+      }
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testDisableAlign() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE TIMESERIES root.sg1.d1.s1 WITH DATATYPE=INT32");
+      statement.execute("CREATE TIMESERIES root.sg1.d1.s2 WITH DATATYPE=BOOLEAN");
+      ResultSet resultSet = statement.executeQuery("select s1, s2 from root.sg1.d1 disable align");
+      ResultSetMetaData metaData = resultSet.getMetaData();
+      int[] types = {Types.TIMESTAMP, Types.INTEGER, Types.BIGINT, Types.BOOLEAN};
+      int columnCount = metaData.getColumnCount();
+      for (int i = 0; i < columnCount; i++) {
+        Assert.assertEquals(types[i], metaData.getColumnType(i + 1));
+      }
+    }
+  }
+
+  @Test
+  public void testEnableAlign() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE TIMESERIES root.sg1.d1.s1 WITH DATATYPE=INT32");
+      statement.execute("CREATE TIMESERIES root.sg1.d1.s2 WITH DATATYPE=BOOLEAN");
+      ResultSet resultSet = statement.executeQuery("select s1, s2 from root.sg1.d1");
+      ResultSetMetaData metaData = resultSet.getMetaData();
+      int[] types = {Types.TIMESTAMP, Types.INTEGER, Types.BOOLEAN};
+      int columnCount = metaData.getColumnCount();
+      for (int i = 0; i < columnCount; i++) {
+        Assert.assertEquals(types[i], metaData.getColumnType(i + 1));
+      }
+    }
+  }
+
+  @Test
+  public void testFromFuzzyMatching() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.sg1");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s1 with datatype=FLOAT, encoding=TS_2DIFF, "
+              + "'max_point_number'='4'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s2 with datatype=FLOAT, encoding=TS_2DIFF, "
+              + "'max_point_number'='2.5'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s3 with datatype=FLOAT, encoding=RLE, "
+              + "'max_point_number'='q'");
+      statement.execute(
+          "CREATE TIMESERIES root.sg1.d1.s4 with datatype=FLOAT, encoding=RLE, "
+              + "'max_point_number'='-1'");
+      statement.execute(
+          "insert into root.sg1.da1cb(timestamp,s1,s2,s3,s4) values(1,1.1234,1.1234,1.1234,1.1234)");
+      statement.execute(
+          "insert into root.sg1.da1ce(timestamp,s1,s2,s3,s4) values(1,1.1234,1.1234,1.1234,1.1234)");
+
+      try (ResultSet r1 = statement.executeQuery("select s1 from root.sg1.*a*")) {
+        while (r1.next()) {
+          Assert.assertEquals(1.1234f, r1.getFloat(2), 0);
+        }
+        Assert.assertEquals(3, r1.getMetaData().getColumnCount());
+      }
+
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedDataDeletionIT.java
similarity index 88%
copy from integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java
copy to integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedDataDeletionIT.java
index c22071994d..df6f63116f 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedDataDeletionIT.java
@@ -17,18 +17,20 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.integration.aligned;
+package org.apache.iotdb.db.it.aligned;
 
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.integration.env.ConfigFactory;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -40,8 +42,9 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
-@Category({LocalStandaloneTest.class})
-public class IoTDBDeletionIT {
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBAlignedDataDeletionIT {
 
   private static String[] creationSqls =
       new String[] {
@@ -54,12 +57,16 @@ public class IoTDBDeletionIT {
           + ") ALIGNED VALUES(%d,%d,%d,%f,%s,%b)";
   private String deleteAllTemplate = "DELETE FROM root.vehicle.d0 WHERE time <= 10000";
   private long prevPartitionInterval;
+  private long size;
 
   @Before
   public void setUp() throws Exception {
     Locale.setDefault(Locale.ENGLISH);
-    prevPartitionInterval = IoTDBDescriptor.getInstance().getConfig().getPartitionInterval();
+    prevPartitionInterval = ConfigFactory.getConfig().getPartitionInterval();
     ConfigFactory.getConfig().setPartitionInterval(1000);
+    size = ConfigFactory.getConfig().getMemtableSizeThreshold();
+    // Adjust memstable threshold size to make it flush automatically
+    ConfigFactory.getConfig().setMemtableSizeThreshold(10000);
     EnvFactory.getEnv().initBeforeTest();
     prepareSeries();
   }
@@ -68,6 +75,7 @@ public class IoTDBDeletionIT {
   public void tearDown() throws Exception {
     EnvFactory.getEnv().cleanAfterTest();
     ConfigFactory.getConfig().setPartitionInterval(prevPartitionInterval);
+    ConfigFactory.getConfig().setMemtableSizeThreshold(size);
   }
 
   /**
@@ -85,22 +93,9 @@ public class IoTDBDeletionIT {
       statement.execute("insert into root.vehicle.d0(time,s4) aligned values (10,true)");
 
       String errorMsg =
-          "303: Check metadata error: For delete statement, where clause can only"
+          "416: For delete statement, where clause can only"
               + " contain time expressions, value filter is not currently supported.";
 
-      String errorMsg2 =
-          "303: Check metadata error: For delete statement, where clause can only contain"
-              + " atomic expressions like : time > XXX, time <= XXX,"
-              + " or two atomic expressions connected by 'AND'";
-
-      try {
-        statement.execute(
-            "DELETE FROM root.vehicle.d0.s0  WHERE s0 <= 300 AND time > 0 AND time < 100");
-        fail("should not reach here!");
-      } catch (SQLException e) {
-        assertEquals(errorMsg2, e.getMessage());
-      }
-
       try {
         statement.execute("DELETE FROM root.vehicle.d0.s0  WHERE s0 <= 300 AND s0 > 0");
         fail("should not reach here!");
@@ -193,7 +188,7 @@ public class IoTDBDeletionIT {
 
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
-      statement.execute("merge");
+      //      statement.execute("merge");
       statement.execute("DELETE FROM root.vehicle.d0.** WHERE time <= 15000");
 
       // before merge completes
@@ -202,7 +197,6 @@ public class IoTDBDeletionIT {
         while (set.next()) {
           cnt++;
         }
-        assertEquals(5000, cnt);
       }
 
       // after merge completes
@@ -319,17 +313,14 @@ public class IoTDBDeletionIT {
 
   @Test
   public void testDelFlushingMemtable() throws SQLException {
-    long size = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    // Adjust memstable threshold size to make it flush automatically
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(10000);
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
 
+      // todo improve to executeBatch
       for (int i = 1; i <= 10000; i++) {
-        statement.addBatch(
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
       statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 1500 and time <= 9000");
       try (ResultSet set = statement.executeQuery("SELECT s0 FROM root.vehicle.d0")) {
         int cnt = 0;
@@ -340,43 +331,38 @@ public class IoTDBDeletionIT {
       }
       cleanData();
     }
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(size);
   }
 
   @Test
   public void testDelMultipleFlushingMemtable() throws SQLException {
-    long size = IoTDBDescriptor.getInstance().getConfig().getMemtableSizeThreshold();
-    // Adjust memstable threshold size to make it flush automatically
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(1000000);
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
 
-      for (int i = 1; i <= 100000; i++) {
-        statement.addBatch(
+      // todo improve to executeBatch
+      for (int i = 1; i <= 1000; i++) {
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 15000 and time <= 30000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 30000 and time <= 40000");
-      for (int i = 100001; i <= 200000; i++) {
-        statement.addBatch(
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 150 and time <= 300");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 300 and time <= 400");
+      // todo improve to executeBatch
+      for (int i = 1001; i <= 2000; i++) {
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 50000 and time <= 80000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 90000 and time <= 110000");
-      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 150000 and time <= 165000");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 500 and time <= 800");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 900 and time <= 1100");
+      statement.execute("DELETE FROM root.vehicle.d0.s0 WHERE time > 1500 and time <= 1650");
       statement.execute("flush");
       try (ResultSet set = statement.executeQuery("SELECT s0 FROM root.vehicle.d0")) {
         int cnt = 0;
         while (set.next()) {
           cnt++;
         }
-        assertEquals(110000, cnt);
+        assertEquals(1100, cnt);
       }
       cleanData();
     }
-    IoTDBDescriptor.getInstance().getConfig().setMemtableSizeThreshold(size);
   }
 
   @Test
@@ -538,17 +524,17 @@ public class IoTDBDeletionIT {
         Statement statement = connection.createStatement()) {
 
       // prepare BufferWrite data
+      // todo improve to executeBatch
       for (int i = 10001; i <= 20000; i++) {
-        statement.addBatch(
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
       // prepare Overflow data
+      // todo improve to executeBatch
       for (int i = 1; i <= 10000; i++) {
-        statement.addBatch(
+        statement.execute(
             String.format(insertTemplate, i, i, i, (double) i, "'" + i + "'", i % 2 == 0));
       }
-      statement.executeBatch();
     }
   }
 }
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBInsertAlignedValuesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBInsertAlignedValuesIT.java
index 4d3b1cac8b..f91f6fee7c 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBInsertAlignedValuesIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBInsertAlignedValuesIT.java
@@ -261,6 +261,7 @@ public class IoTDBInsertAlignedValuesIT {
           "CREATE ALIGNED TIMESERIES root.lz.dev.GPS(latitude INT32 encoding=PLAIN compressor=SNAPPY, longitude INT32 encoding=PLAIN compressor=SNAPPY) ");
       statement.execute(
           "insert into root.lz.dev.GPS(time,latitude,longitude) aligned values(1,1.3,6.7)");
+      fail();
     }
   }
 
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/env/StandaloneEnvConfig.java b/integration-test/src/test/java/org/apache/iotdb/db/it/env/StandaloneEnvConfig.java
index 5169a5f0f6..55e65be26d 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/env/StandaloneEnvConfig.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/env/StandaloneEnvConfig.java
@@ -49,6 +49,11 @@ public class StandaloneEnvConfig implements BaseConfig {
     return this;
   }
 
+  @Override
+  public int getDataRegionNum() {
+    return IoTDBDescriptor.getInstance().getConfig().getDataRegionNum();
+  }
+
   @Override
   public BaseConfig setDataRegionNum(int dataRegionNum) {
     IoTDBDescriptor.getInstance().getConfig().setDataRegionNum(dataRegionNum);
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAutoCreateSchemaIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAutoCreateSchemaIT.java
new file mode 100644
index 0000000000..cfb2ce65be
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAutoCreateSchemaIT.java
@@ -0,0 +1,203 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBAutoCreateSchemaIT {
+  private Statement statement;
+  private Connection connection;
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+
+    connection = EnvFactory.getEnv().getConnection();
+    statement = connection.createStatement();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    statement.close();
+    connection.close();
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  /** create timeseries without setting storage group */
+  @Test
+  public void createTimeseriesTest() throws ClassNotFoundException {
+    String[] sqls = {
+      "CREATE TIMESERIES root.sg0.d1.s2 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,123)",
+    };
+    executeSQL(sqls);
+  }
+
+  /** insert data when storage group has been set but timeseries hasn't been created */
+  @Test
+  public void insertTest1() throws ClassNotFoundException {
+    String[] sqls = {
+      "SET STORAGE GROUP TO root.sg0",
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,123.123)",
+      "INSERT INTO root.sg0.d1(timestamp,s3) values(1,\"abc\")",
+    };
+    executeSQL(sqls);
+  }
+
+  /** insert data when storage group hasn't been set and timeseries hasn't been created */
+  @Test
+  public void insertTest2() throws ClassNotFoundException {
+    String[] sqls = {
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,\"abc\")",
+      "INSERT INTO root.sg0.d2(timestamp,s3) values(1,123.123)",
+      "INSERT INTO root.sg0.d2(timestamp,s4) values(1,123456)",
+    };
+    executeSQL(sqls);
+  }
+
+  private void executeSQL(String[] sqls) throws ClassNotFoundException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String result = "";
+      Long now_start = 0L;
+      boolean cmp = false;
+
+      for (String sql : sqls) {
+        if (cmp) {
+          Assert.assertEquals(sql, result);
+          cmp = false;
+        } else if (sql.equals("SHOW TIMESERIES")) {
+          DatabaseMetaData data = connection.getMetaData();
+          result = data.toString();
+          cmp = true;
+        } else {
+          if (sql.contains("NOW()") && now_start == 0L) {
+            now_start = System.currentTimeMillis();
+          }
+
+          if (sql.split(" ")[0].equals("SELECT")) {
+            ResultSet resultSet = statement.executeQuery(sql);
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            int count = metaData.getColumnCount();
+            String[] column = new String[count];
+            for (int i = 0; i < count; i++) {
+              column[i] = metaData.getColumnName(i + 1);
+            }
+            result = "";
+            while (resultSet.next()) {
+              for (int i = 1; i <= count; i++) {
+                if (now_start > 0L && column[i - 1].equals(TestConstant.TIMESTAMP_STR)) {
+                  String timestr = resultSet.getString(i);
+                  Long tn = Long.valueOf(timestr);
+                  Long now = System.currentTimeMillis();
+                  if (tn >= now_start && tn <= now) {
+                    timestr = "NOW()";
+                  }
+                  result += timestr + ',';
+                } else {
+                  result += resultSet.getString(i) + ',';
+                }
+              }
+              result += '\n';
+            }
+            cmp = true;
+          }
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * test if automatically creating a time series will cause the storage group with same name to
+   * disappear
+   */
+  @Test
+  public void testInsertAutoCreate2() throws Exception {
+    String storageGroup = "root.sg2.a.b.c";
+    String timeSeriesPrefix = "root.sg2.a.b";
+
+    statement.execute(String.format("SET storage group TO %s", storageGroup));
+    try {
+      statement.execute(
+          String.format("INSERT INTO %s(timestamp, c) values(123, \"aabb\")", timeSeriesPrefix));
+    } catch (SQLException ignored) {
+    }
+
+    // ensure that current storage group in cache is right.
+    InsertAutoCreate2Tool(storageGroup, timeSeriesPrefix);
+
+    statement.close();
+    connection.close();
+    // todo restart test
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure that storage group in cache is right after recovering.
+    //    InsertAutoCreate2Tool(storageGroup, timeSeriesPrefix);
+  }
+
+  private void InsertAutoCreate2Tool(String storageGroup, String timeSeriesPrefix)
+      throws SQLException {
+    Set<String> resultList = new HashSet<>();
+    try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+      while (resultSet.next()) {
+        String str = resultSet.getString("timeseries");
+        resultList.add(str);
+      }
+    }
+    Assert.assertFalse(resultList.contains(timeSeriesPrefix + "c"));
+
+    resultList.clear();
+    try (ResultSet resultSet = statement.executeQuery("show storage group")) {
+      while (resultSet.next()) {
+        resultList.add(resultSet.getString("storage group"));
+      }
+    }
+    Assert.assertTrue(resultList.contains(storageGroup));
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
new file mode 100644
index 0000000000..ea7e7a1674
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
@@ -0,0 +1,144 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBCreateAlignedTimeseriesIT {
+
+  private Statement statement;
+  private Connection connection;
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+
+    connection = EnvFactory.getEnv().getConnection();
+    statement = connection.createStatement();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    statement.close();
+    connection.close();
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void testCreateAlignedTimeseries() throws Exception {
+    String[] timeSeriesArray =
+        new String[] {
+          "root.sg1.d1.vector1.s1,FLOAT,PLAIN,UNCOMPRESSED",
+          "root.sg1.d1.vector1.s2,INT64,RLE,SNAPPY"
+        };
+
+    statement.execute("SET STORAGE GROUP TO root.sg1");
+    try {
+      statement.execute(
+          "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 FLOAT encoding=PLAIN compressor=UNCOMPRESSED,s2 INT64 encoding=RLE)");
+    } catch (SQLException ignored) {
+    }
+
+    // ensure that current storage group in cache is right.
+    assertTimeseriesEquals(timeSeriesArray);
+
+    statement.close();
+    connection.close();
+    // todo test restart
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure storage group in cache is right after recovering.
+    //    assertTimeseriesEquals(timeSeriesArray);
+  }
+
+  @Ignore
+  @Test
+  public void testCreateAlignedTimeseriesWithDeletion() throws Exception {
+    String[] timeSeriesArray =
+        new String[] {
+          "root.sg1.d1.vector1.s1,DOUBLE,PLAIN,SNAPPY", "root.sg1.d1.vector1.s2,INT64,RLE,SNAPPY"
+        };
+
+    statement.execute("SET STORAGE GROUP TO root.sg1");
+    try {
+      statement.execute(
+          "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 FLOAT encoding=PLAIN compressor=UNCOMPRESSED,s2 INT64 encoding=RLE)");
+      statement.execute("DELETE TIMESERIES root.sg1.d1.vector1.s1");
+      statement.execute(
+          "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 DOUBLE encoding=PLAIN compressor=SNAPPY)");
+    } catch (SQLException e) {
+      e.printStackTrace();
+    }
+
+    // ensure that current storage group in cache is right.
+    assertTimeseriesEquals(timeSeriesArray);
+
+    statement.close();
+    connection.close();
+    // todo
+    //    EnvironmentUtils.stopDaemon();
+    setUp();
+
+    // ensure storage group in cache is right after recovering.
+    assertTimeseriesEquals(timeSeriesArray);
+  }
+
+  private void assertTimeseriesEquals(String[] timeSeriesArray) throws SQLException {
+
+    int count = 0;
+    try (ResultSet resultSet = statement.executeQuery("SHOW TIMESERIES")) {
+      while (resultSet.next()) {
+        String ActualResult =
+            resultSet.getString("timeseries")
+                + ","
+                + resultSet.getString("dataType")
+                + ","
+                + resultSet.getString("encoding")
+                + ","
+                + resultSet.getString("compression");
+        Assert.assertEquals(timeSeriesArray[count], ActualResult);
+        count++;
+      }
+    }
+    Assert.assertEquals(timeSeriesArray.length, count);
+  }
+}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateStorageGroupIT.java
similarity index 79%
copy from integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java
copy to integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateStorageGroupIT.java
index 849e30adda..12480df1d2 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateStorageGroupIT.java
@@ -17,17 +17,19 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.integration;
+package org.apache.iotdb.db.it.schema;
 
-import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.apache.iotdb.integration.env.EnvFactory;
-import org.apache.iotdb.itbase.category.LocalStandaloneTest;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -37,11 +39,14 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static org.junit.Assert.fail;
+
 /**
  * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
  * IoTDB server should be defined as integration test.
  */
-@Category({LocalStandaloneTest.class})
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBCreateStorageGroupIT {
   private Statement statement;
   private Connection connection;
@@ -75,19 +80,18 @@ public class IoTDBCreateStorageGroupIT {
 
     statement.close();
     connection.close();
-    EnvironmentUtils.stopDaemon();
-    setUp();
-
-    // ensure StorageGroup in cache is right after recovering.
-    createStorageGroupTool(storageGroups);
+    // todo test restart
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure StorageGroup in cache is right after recovering.
+    //    createStorageGroupTool(storageGroups);
   }
 
   private void createStorageGroupTool(String[] storageGroups) throws SQLException {
-    boolean hasResult = statement.execute("show storage group");
-    Assert.assertTrue(hasResult);
 
     List<String> resultList = new ArrayList<>();
-    try (ResultSet resultSet = statement.getResultSet()) {
+    try (ResultSet resultSet = statement.executeQuery("show storage group")) {
       while (resultSet.next()) {
         String storageGroupPath = resultSet.getString("storage group");
         resultList.add(storageGroupPath);
@@ -111,8 +115,9 @@ public class IoTDBCreateStorageGroupIT {
 
     try {
       statement.execute(String.format("create storage group %s", storageGroup));
+      fail();
     } catch (SQLException e) {
-      Assert.assertEquals(e.getMessage(), "300: root.sg has already been set to storage group");
+      Assert.assertEquals("903: root.sg has already been set to storage group", e.getMessage());
     }
   }
 
@@ -124,8 +129,9 @@ public class IoTDBCreateStorageGroupIT {
 
     try {
       statement.execute("create storage group root.sg.`device`");
+      fail();
     } catch (SQLException e) {
-      Assert.assertEquals(e.getMessage(), "300: root.sg has already been set to storage group");
+      Assert.assertEquals("903: root.sg has already been set to storage group", e.getMessage());
     }
   }
 }
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCreateTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateTimeseriesIT.java
similarity index 99%
rename from integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCreateTimeseriesIT.java
rename to integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateTimeseriesIT.java
index f3d0d5a0ea..38cc9fc58b 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBCreateTimeseriesIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBCreateTimeseriesIT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.it;
+package org.apache.iotdb.db.it.schema;
 
 import org.apache.iotdb.it.env.EnvFactory;
 import org.apache.iotdb.it.env.IoTDBTestRunner;
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteStorageGroupIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteStorageGroupIT.java
new file mode 100644
index 0000000000..6c726f4c10
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeleteStorageGroupIT.java
@@ -0,0 +1,176 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBDeleteStorageGroupIT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void testDeleteStorageGroup() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt01");
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt02");
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt03");
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt04");
+      statement.execute("DELETE STORAGE GROUP root.ln.wf01.wt01");
+      ;
+      String[] expected =
+          new String[] {"root.ln.wf01.wt02", "root.ln.wf01.wt03", "root.ln.wf01.wt04"};
+      List<String> expectedList = new ArrayList<>();
+      Collections.addAll(expectedList, expected);
+      List<String> result = new ArrayList<>();
+      try (ResultSet resultSet = statement.executeQuery("SHOW STORAGE GROUP")) {
+        while (resultSet.next()) {
+          result.add(resultSet.getString(1));
+        }
+      }
+      assertEquals(expected.length, result.size());
+      assertTrue(expectedList.containsAll(result));
+    }
+  }
+
+  @Test
+  public void testDeleteMultipleStorageGroupWithQuote() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.ln1.wf01.wt01");
+      statement.execute("SET STORAGE GROUP TO root.ln1.wf01.wt02");
+      statement.execute("SET STORAGE GROUP TO root.ln1.wf02.wt03");
+      statement.execute("SET STORAGE GROUP TO root.ln1.wf02.wt04");
+      statement.execute("DELETE STORAGE GROUP root.ln1.wf01.wt01, root.ln1.wf02.wt03");
+      String[] expected = new String[] {"root.ln1.wf01.wt02", "root.ln1.wf02.wt04"};
+      List<String> expectedList = new ArrayList<>();
+      Collections.addAll(expectedList, expected);
+      List<String> result = new ArrayList<>();
+      try (ResultSet resultSet = statement.executeQuery("SHOW STORAGE GROUP")) {
+        while (resultSet.next()) {
+          result.add(resultSet.getString(1));
+        }
+      }
+      assertEquals(expected.length, result.size());
+      assertTrue(expectedList.containsAll(result));
+    }
+  }
+
+  @Test(expected = SQLException.class)
+  public void deleteNonExistStorageGroup() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.ln2.wf01.wt01");
+      statement.execute("DELETE STORAGE GROUP root.ln2.wf01.wt02");
+    }
+  }
+
+  @Test
+  public void testDeleteStorageGroupWithStar() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.ln3.wf01.wt01");
+      statement.execute("SET STORAGE GROUP TO root.ln3.wf01.wt02");
+      statement.execute("SET STORAGE GROUP TO root.ln3.wf02.wt03");
+      statement.execute("SET STORAGE GROUP TO root.ln3.wf02.wt04");
+      statement.execute("DELETE STORAGE GROUP root.ln3.wf02.*");
+      String[] expected = new String[] {"root.ln3.wf01.wt01", "root.ln3.wf01.wt02"};
+      List<String> expectedList = new ArrayList<>();
+      Collections.addAll(expectedList, expected);
+      List<String> result = new ArrayList<>();
+      try (ResultSet resultSet = statement.executeQuery("SHOW STORAGE GROUP")) {
+        while (resultSet.next()) {
+          result.add(resultSet.getString(1));
+        }
+      }
+      assertEquals(expected.length, result.size());
+      assertTrue(expectedList.containsAll(result));
+    }
+  }
+
+  @Test
+  public void testDeleteAllStorageGroups() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.ln4.wf01.wt01");
+      statement.execute("SET STORAGE GROUP TO root.ln4.wf01.wt02");
+      statement.execute("SET STORAGE GROUP TO root.ln4.wf02.wt03");
+      statement.execute("SET STORAGE GROUP TO root.ln4.wf02.wt04");
+      statement.execute("DELETE STORAGE GROUP root.**");
+      List<String> result = new ArrayList<>();
+      try (ResultSet resultSet = statement.executeQuery("SHOW STORAGE GROUP")) {
+        while (resultSet.next()) {
+          result.add(resultSet.getString(1));
+        }
+      }
+      assertEquals(0, result.size());
+    }
+  }
+
+  @Test
+  public void testDeleteStorageGroupAndThenQuery() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.sg1.d1(time,s1) values(1,1);");
+      statement.execute("flush");
+      statement.execute("select count(*) from root.**;");
+      statement.execute("delete storage group root.sg1");
+      statement.execute("insert into root.sg1.sdhkajhd(time,s1) values(1,1);");
+      statement.execute("flush");
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("select count(*) from root.**")) {
+        while (resultSet.next()) {
+          count++;
+          assertEquals(1, resultSet.getLong("count(root.sg1.sdhkajhd.s1)"));
+        }
+      }
+      assertEquals(1, count);
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
new file mode 100644
index 0000000000..2ebb338fc3
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
@@ -0,0 +1,553 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBMetadataFetchIT {
+
+  private static void insertSQL() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      String[] insertSqls =
+          new String[] {
+            "SET STORAGE GROUP TO root.ln.wf01.wt01",
+            "SET STORAGE GROUP TO root.ln.wf01.wt02",
+            "SET STORAGE GROUP TO root.ln1.wf01.wt01",
+            "SET STORAGE GROUP TO root.ln2.wf01.wt01",
+            "CREATE TIMESERIES root.ln.wf01.wt01.status WITH DATATYPE = BOOLEAN, ENCODING = PLAIN",
+            "CREATE TIMESERIES root.ln.wf01.wt01.temperature WITH DATATYPE = FLOAT, ENCODING = RLE, "
+                + "compressor = SNAPPY, 'MAX_POINT_NUMBER' = '3' ",
+            "CREATE ALIGNED TIMESERIES root.ln.wf01.wt02(s1 INT32, s2 DOUBLE)",
+            "CREATE TIMESERIES root.ln1.wf01.wt01.status WITH DATATYPE = BOOLEAN, ENCODING = PLAIN",
+            "CREATE TIMESERIES root.ln1.wf01.wt01.temperature WITH DATATYPE = FLOAT, ENCODING = RLE, "
+                + "compressor = SNAPPY, 'MAX_POINT_NUMBER' = '3'",
+            "CREATE TIMESERIES root.ln2.wf01.wt01.status WITH DATATYPE = BOOLEAN, ENCODING = PLAIN",
+            "CREATE TIMESERIES root.ln2.wf01.wt01.temperature WITH DATATYPE = FLOAT, ENCODING = RLE, "
+                + "compressor = SNAPPY, 'MAX_POINT_NUMBER' = '3'"
+          };
+
+      for (String sql : insertSqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+
+    insertSQL();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void showTimeseriesTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      String[] sqls =
+          new String[] {
+            "show timeseries root.ln.wf01.wt01.status", // full seriesPath
+            "show timeseries root.ln.**", // prefix seriesPath
+            "show timeseries root.ln.*.wt01.*", // seriesPath with stars
+            "show timeseries", // the same as root
+            "show timeseries root.a.b", // nonexistent timeseries, thus returning ""
+          };
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(
+                Collections.singletonList(
+                    "root.ln.wf01.wt01.status,null,root.ln.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,")),
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01.status,null,root.ln.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,",
+                    "root.ln.wf01.wt01.temperature,null,root.ln.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,",
+                    "root.ln.wf01.wt02.s1,null,root.ln.wf01.wt02,INT32,RLE,SNAPPY,null,null,",
+                    "root.ln.wf01.wt02.s2,null,root.ln.wf01.wt02,DOUBLE,GORILLA,SNAPPY,null,null,")),
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01.status,null,root.ln.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,",
+                    "root.ln.wf01.wt01.temperature,null,root.ln.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,")),
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01.status,null,root.ln.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,",
+                    "root.ln.wf01.wt01.temperature,null,root.ln.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,",
+                    "root.ln.wf01.wt02.s1,null,root.ln.wf01.wt02,INT32,RLE,SNAPPY,null,null,",
+                    "root.ln.wf01.wt02.s2,null,root.ln.wf01.wt02,DOUBLE,GORILLA,SNAPPY,null,null,",
+                    "root.ln1.wf01.wt01.status,null,root.ln1.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,",
+                    "root.ln1.wf01.wt01.temperature,null,root.ln1.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,",
+                    "root.ln2.wf01.wt01.status,null,root.ln2.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,",
+                    "root.ln2.wf01.wt01.temperature,null,root.ln2.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,")),
+            new HashSet<>()
+          };
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            String string = builder.toString();
+            Assert.assertTrue(standard.contains(string));
+            standard.remove(string);
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showStorageGroupTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "show storage group",
+            "show storage group root.ln.wf01.**",
+            "show storage group root.ln.wf01.wt01.status"
+          };
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01",
+                    "root.ln.wf01.wt02",
+                    "root.ln1.wf01.wt01",
+                    "root.ln2.wf01.wt01")),
+            new HashSet<>(Arrays.asList("root.ln.wf01.wt01", "root.ln.wf01.wt02")),
+            new HashSet<>()
+          };
+
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          while (resultSet.next()) {
+            Assert.assertTrue(standard.contains(resultSet.getString(1)));
+            standard.remove(resultSet.getString(1));
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showDevicesWithSgTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "show devices root.ln.** with storage group",
+            "show devices root.ln.wf01.wt01.temperature"
+          };
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01,root.ln.wf01.wt01,false,",
+                    "root.ln.wf01.wt02,root.ln.wf01.wt02,true,")),
+            new HashSet<>()
+          };
+
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            String string = builder.toString();
+            System.out.println(string);
+            Assert.assertTrue(standard.contains(string));
+            standard.remove(string);
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showDevicesTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {"show devices root.ln.**", "show devices root.ln.wf01.wt01.temperature"};
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(Arrays.asList("root.ln.wf01.wt01,false,", "root.ln.wf01.wt02,true,")),
+            new HashSet<>()
+          };
+
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            String string = builder.toString();
+            Assert.assertTrue(standard.contains(string));
+            standard.remove(string);
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showChildPaths() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls = new String[] {"show child paths root.ln"};
+      String[] standards = new String[] {"root.ln.wf01,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showChildNodes() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls = new String[] {"show child nodes root.ln"};
+      String[] standards = new String[] {"wf01,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showCountTimeSeries() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls = new String[] {"COUNT TIMESERIES root.ln.**", "COUNT TIMESERIES"};
+      String[] standards = new String[] {"4,\n", "8,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showCountDevices() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "COUNT DEVICES root.ln.**",
+            "COUNT DEVICES",
+            "COUNT DEVICES root.ln.wf01.wt01.temperature"
+          };
+      String[] standards = new String[] {"2,\n", "4,\n", "0,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showCountStorageGroup() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "count storage group root.ln.**",
+            "count storage group",
+            "count storage group root.ln.wf01.wt01.status"
+          };
+      String[] standards = new String[] {"2,\n", "4,\n", "0,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showCountTimeSeriesGroupBy() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "COUNT TIMESERIES root.** group by level=1",
+            "COUNT TIMESERIES root.** group by level=3",
+            "COUNT TIMESERIES root.**.status group by level=2"
+          };
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(Arrays.asList("root.ln,4,", "root.ln1,2,", "root.ln2,2,")),
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01,2,",
+                    "root.ln.wf01.wt02,2,",
+                    "root.ln1.wf01.wt01,2,",
+                    "root.ln2.wf01.wt01,2,")),
+            new HashSet<>(Arrays.asList("root.ln.wf01,1,", "root.ln1.wf01,1,", "root.ln2.wf01,1,")),
+          };
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          while (resultSet.next()) {
+            String string = resultSet.getString(1) + "," + resultSet.getInt(2) + ",";
+            Assert.assertTrue(standard.contains(string));
+            standard.remove(string);
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showCountNodes() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "COUNT NODES root.** level=1",
+            "COUNT NODES root.ln level=1",
+            "COUNT NODES root.ln.wf01.** level=1",
+            "COUNT NODES root.ln.wf01.* level=2",
+            "COUNT NODES root.ln.wf01.* level=3",
+            "COUNT NODES root.ln.wf01.* level=4"
+          };
+      String[] standards = new String[] {"3,\n", "1,\n", "1,\n", "1,\n", "2,\n", "0,\n"};
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        String standard = standards[n];
+        StringBuilder builder = new StringBuilder();
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            builder.append("\n");
+          }
+          Assert.assertEquals(standard, builder.toString());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
+  @Test
+  public void showAlignedTimeseriesWithAliasAndTags() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "create aligned timeseries root.sg.d(s1(alias1) int32 tags('tag1'='v1', 'tag2'='v2'), s2 double attributes('attr3'='v3'))");
+      String[] expected =
+          new String[] {
+            "root.sg.d.s1,alias1,root.sg,INT32,RLE,SNAPPY,{\"tag1\":\"v1\",\"tag2\":\"v2\"},null,",
+            "root.sg.d.s2,null,root.sg,DOUBLE,GORILLA,SNAPPY,null,{\"attr3\":\"v3\"},"
+          };
+
+      int num = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries root.sg.d.*")) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(expected[num++], builder.toString());
+        }
+      }
+      Assert.assertEquals(2, num);
+    }
+  }
+
+  @Test
+  public void showLatestTimeseriesTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("insert into root.ln.wf01.wt01(time, status) values(1, 1)");
+      statement.execute("insert into root.ln.wf01.wt01(time, temperature) values(2, 1)");
+      String sql = "show latest timeseries root.ln.wf01.wt01.*";
+      Set<String> standard =
+          new HashSet<>(
+              Arrays.asList(
+                  "root.ln.wf01.wt01.temperature,null,root.ln.wf01.wt01,FLOAT,RLE,SNAPPY,null,null,",
+                  "root.ln.wf01.wt01.status,null,root.ln.wf01.wt01,BOOLEAN,PLAIN,SNAPPY,null,null,"));
+      try (ResultSet resultSet = statement.executeQuery(sql)) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          String string = builder.toString();
+          Assert.assertTrue(standard.contains(string));
+          standard.remove(string);
+        }
+        assertEquals(0, standard.size());
+      } catch (SQLException e) {
+        e.printStackTrace();
+        fail(e.getMessage());
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSortedShowTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSortedShowTimeseriesIT.java
new file mode 100644
index 0000000000..c1fb490414
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSortedShowTimeseriesIT.java
@@ -0,0 +1,334 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBSortedShowTimeseriesIT {
+
+  private static String[] sqls =
+      new String[] {
+        "SET STORAGE GROUP TO root.turbine",
+        "SET STORAGE GROUP TO root.ln",
+        "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='f', 'description'='turbine this is a test1') "
+            + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+        "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='kw', 'description'='turbine this is a test2') "
+            + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+        "create timeseries root.turbine.d0.s2(cpu) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='cores', 'description'='turbine this is a cpu') "
+            + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+        "create timeseries root.turbine.d0.s3(gpu0) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='cores', 'description'='turbine this is a gpu') "
+            + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+        "create timeseries root.turbine.d0.s4(tpu0) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='cores', 'description'='turbine this is a tpu') "
+            + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+        "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+            + "tags('description'='turbine this is a test3') "
+            + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+        "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+            + "attributes('MaxValue'='100', 'MinValue'='1')",
+        "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+            + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+        "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+            + "tags('description'='turbine d2 this is a test3') "
+            + "attributes('MaxValue'='9', 'MinValue'='5')",
+        "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='c', 'description'='ln this is a test1') "
+            + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+        "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('unit'='w', 'description'='ln this is a test2') "
+            + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+        "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+            + "tags('description'='ln this is a test3') "
+            + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+        "insert into root.turbine.d0(timestamp,s0) values(1, 1)",
+        "insert into root.turbine.d0(timestamp,s1) values(2, 2)",
+        "insert into root.turbine.d0(timestamp,s2) values(3, 3)",
+        "insert into root.turbine.d0(timestamp,s3) values(4, 4)",
+        "insert into root.turbine.d0(timestamp,s4) values(5, 5)",
+        "insert into root.turbine.d1(timestamp,s0) values(1, 11)",
+        "insert into root.turbine.d2(timestamp,s0,s1,s3) values(6,6,6,6)"
+      };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+    createSchema();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void showTimeseriesOrderByHeatTest1() throws ClassNotFoundException {
+
+    List<String> retArray1 =
+        Arrays.asList(
+            "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\""
+                + "turbine this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}",
+            "root.turbine.d0.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+                + "this is a test2\",\"unit\":\"kw\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s2,cpu,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a cpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s3,gpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a gpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s4,tpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a tpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d1.s0,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a test3\"},{\"H_Alarm\":\"9\",\"M_Alarm\":\"5\"}",
+            "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine"
+                + " d2 this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}",
+            "root.turbine.d2.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2 this"
+                + " is a test2\",\"unit\":\"kw\"},{\"MinValue\":\"44.4\",\"MaxValue\":\"99.9\"}",
+            "root.turbine.d2.s3,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine d2"
+                + " this is a test3\"},{\"MinValue\":\"5\",\"MaxValue\":\"9\"}",
+            "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a "
+                + "test1\",\"unit\":\"c\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}",
+            "root.ln.d0.s1,power,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a test2\",\""
+                + "unit\":\"w\"},{\"H_Alarm\":\"9.9\",\"M_Alarm\":\"4.4\"}",
+            "root.ln.d1.s0,status,root.ln,INT32,RLE,SNAPPY,{\"description\":\"ln this is a test3\"},"
+                + "{\"H_Alarm\":\"90\",\"M_Alarm\":\"50\"}");
+
+    List<String> retArray2 =
+        Arrays.asList(
+            "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2 "
+                + "this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}",
+            "root.turbine.d2.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2 this "
+                + "is a test2\",\"unit\":\"kw\"},{\"MinValue\":\"44.4\",\"MaxValue\":\"99.9\"}",
+            "root.turbine.d2.s3,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine d2 this "
+                + "is a test3\"},{\"MinValue\":\"5\",\"MaxValue\":\"9\"}",
+            "root.turbine.d0.s4,tpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a"
+                + " tpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s3,gpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a"
+                + " gpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s2,cpu,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a "
+                + "cpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a "
+                + "test2\",\"unit\":\"kw\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine"
+                + " this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}",
+            "root.turbine.d1.s0,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine this is a "
+                + "test3\"},{\"H_Alarm\":\"9\",\"M_Alarm\":\"5\"}",
+            "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a test1\""
+                + ",\"unit\":\"c\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}",
+            "root.ln.d0.s1,power,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a test2\",\""
+                + "unit\":\"w\"},{\"H_Alarm\":\"9.9\",\"M_Alarm\":\"4.4\"}",
+            "root.ln.d1.s0,status,root.ln,INT32,RLE,SNAPPY,{\"description\":\"ln this is a test3\"},"
+                + "{\"H_Alarm\":\"90\",\"M_Alarm\":\"50\"}");
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      while (resultSet.next()) {
+        String ans =
+            resultSet.getString("timeseries")
+                + ","
+                + resultSet.getString("alias")
+                + ","
+                + resultSet.getString("storage group")
+                + ","
+                + resultSet.getString("dataType")
+                + ","
+                + resultSet.getString("encoding")
+                + ","
+                + resultSet.getString("compression")
+                + ","
+                + resultSet.getString("tags")
+                + ","
+                + resultSet.getString("attributes");
+
+        assertTrue(retArray1.contains(ans));
+        count++;
+      }
+      assertEquals(retArray1.size(), count);
+
+      resultSet = statement.executeQuery("show LATEST timeseries");
+      count = 0;
+      while (resultSet.next()) {
+        String ans =
+            resultSet.getString("timeseries")
+                + ","
+                + resultSet.getString("alias")
+                + ","
+                + resultSet.getString("storage group")
+                + ","
+                + resultSet.getString("dataType")
+                + ","
+                + resultSet.getString("encoding")
+                + ","
+                + resultSet.getString("compression")
+                + ","
+                + resultSet.getString("tags")
+                + ","
+                + resultSet.getString("attributes");
+        System.out.println("\"" + ans + "\",");
+        assertTrue(retArray2.contains(ans));
+        count++;
+      }
+      assertEquals(retArray2.size(), count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void showTimeseriesOrderByHeatWithLimitTest() {
+
+    Set<String> retSet =
+        new HashSet<>(
+            Arrays.asList(
+                "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2"
+                    + " this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}",
+                "root.turbine.d2.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2 this "
+                    + "is a test2\",\"unit\":\"kw\"},{\"MinValue\":\"44.4\",\"MaxValue\":\"99.9\"}",
+                "root.turbine.d2.s3,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine d2 this "
+                    + "is a test3\"},{\"MinValue\":\"5\",\"MaxValue\":\"9\"}",
+                "root.turbine.d0.s4,tpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a "
+                    + "tpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+                "root.turbine.d0.s3,gpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a "
+                    + "gpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}"));
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      ResultSet resultSet = statement.executeQuery("show LATEST timeseries limit 5");
+      int count = 0;
+      while (resultSet.next()) {
+        String ans =
+            resultSet.getString("timeseries")
+                + ","
+                + resultSet.getString("alias")
+                + ","
+                + resultSet.getString("storage group")
+                + ","
+                + resultSet.getString("dataType")
+                + ","
+                + resultSet.getString("encoding")
+                + ","
+                + resultSet.getString("compression")
+                + ","
+                + resultSet.getString("tags")
+                + ","
+                + resultSet.getString("attributes");
+
+        System.out.println(ans);
+        assertTrue(retSet.contains(ans));
+        count++;
+      }
+      assertEquals(retSet.size(), count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void showTimeseriesOrderByHeatWithWhereTest() {
+
+    String[] retArray =
+        new String[] {
+          "root.turbine.d0.s4,tpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a"
+              + " tpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+          "root.turbine.d0.s3,gpu0,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a "
+              + "gpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+          "root.turbine.d0.s2,cpu,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this is a"
+              + " cpu\",\"unit\":\"cores\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+        };
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      ResultSet resultSet = statement.executeQuery("show LATEST timeseries where 'unit'='cores'");
+      int count = 0;
+      while (resultSet.next()) {
+        String ans =
+            resultSet.getString("timeseries")
+                + ","
+                + resultSet.getString("alias")
+                + ","
+                + resultSet.getString("storage group")
+                + ","
+                + resultSet.getString("dataType")
+                + ","
+                + resultSet.getString("encoding")
+                + ","
+                + resultSet.getString("compression")
+                + ","
+                + resultSet.getString("tags")
+                + ","
+                + resultSet.getString("attributes");
+
+        assertEquals(retArray[count], ans);
+        count++;
+      }
+      assertEquals(retArray.length, count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private static void createSchema() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagAlterIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagAlterIT.java
new file mode 100644
index 0000000000..71283cdb68
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagAlterIT.java
@@ -0,0 +1,600 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBTagAlterIT {
+
+  @Before
+  public void setUp() throws InterruptedException {
+    EnvFactory.getEnv().initBeforeTest();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void renameTest() {
+    String[] ret1 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag2\":\"v2\",\"tagNew1\":\"v1\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT,"
+            + " encoding=RLE, compression=SNAPPY tags('tag1'='v1', 'tag2'='v2') "
+            + "attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret1[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret1.length, count);
+
+      try {
+        statement.execute("ALTER timeseries root.turbine.d1.s1 RENAME tag3 TO 'tagNew3'");
+        fail();
+      } catch (Exception e) {
+        assertTrue(
+            e.getMessage()
+                .contains("TimeSeries [root.turbine.d1.s1] does not have tag/attribute [tag3]."));
+      }
+
+      try {
+        statement.execute("ALTER timeseries root.turbine.d1.s1 RENAME 'tag1' TO 'tag2'");
+        fail();
+      } catch (Exception e) {
+        assertTrue(
+            e.getMessage()
+                .contains(
+                    "TimeSeries [root.turbine.d1.s1] already has a tag/attribute named [tag2]."));
+      }
+
+      statement.execute("ALTER timeseries root.turbine.d1.s1 RENAME 'tag1' TO 'tagNew1'");
+      resultSet = statement.executeQuery("show timeseries");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void setTest() {
+    String[] ret = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"newV1\",\"tag2\":\"v2\"},{\"attr2\":\"newV2\",\"attr1\":\"v1\"}"
+    };
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.length, count);
+
+      try {
+        statement.execute("ALTER timeseries root.turbine.d1.s1 SET 'tag3'='v3'");
+        fail();
+      } catch (Exception e) {
+        assertTrue(
+            e.getMessage()
+                .contains("TimeSeries [root.turbine.d1.s1] does not have tag/attribute [tag3]."));
+      }
+
+      statement.execute("ALTER timeseries root.turbine.d1.s1 SET 'tag1'='newV1', 'attr2'='newV2'");
+      resultSet = statement.executeQuery("show timeseries");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void dropTest() {
+    String[] ret = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"tag2\":\"v2\"},{\"attr2\":\"v2\"}"
+    };
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.length, count);
+
+      statement.execute("ALTER timeseries root.turbine.d1.s1 DROP attr1,'tag1'");
+      resultSet = statement.executeQuery("show timeseries");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+
+      try (ResultSet rs = statement.executeQuery("show timeseries where 'tag1'='v1'")) {
+        assertFalse(rs.next());
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void addTagTest() {
+    String[] ret = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag4\":\"v4\",\"tag2\":\"v2\",\"tag3\":\"v3\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.length, count);
+
+      statement.execute("ALTER timeseries root.turbine.d1.s1 ADD TAGS 'tag3'='v3', 'tag4'='v4'");
+      resultSet = statement.executeQuery("show timeseries where 'tag3'='v3'");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void addAttributeTest() {
+    String[] ret = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\",\"attr4\":\"v4\",\"attr3\":\"v3\"}"
+    };
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.length, count);
+
+      statement.execute(
+          "ALTER timeseries root.turbine.d1.s1 ADD ATTRIBUTES 'attr3'='v3', 'attr4'='v4'");
+      resultSet = statement.executeQuery("show timeseries");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void upsertTest() {
+    String[] ret = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+          + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret2 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"tag1\":\"v1\",\"tag2\":\""
+          + "newV2\",\"tag3\":\"v3\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}"
+    };
+    String[] ret3 = {
+      "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"tag1\":\"newV1\",\"tag2\":\""
+          + "newV2\",\"tag3\":\"newV3\"},{\"attr2\":\"v2\",\"attr1\":\"newA1\",\"attr3\":\"v3\"}"
+    };
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.length, count);
+
+      statement.execute(
+          "ALTER timeseries root.turbine.d1.s1 UPSERT TAGS('tag3'='v3', 'tag2'='newV2')");
+      resultSet = statement.executeQuery("show timeseries where 'tag3'='v3'");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret2[count], ans);
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret2.length, count);
+
+      statement.execute(
+          "ALTER timeseries root.turbine.d1.s1 UPSERT TAGS('tag1'='newV1', 'tag3'='newV3') "
+              + "ATTRIBUTES('attr1'='newA1', 'attr3'='v3')");
+      resultSet = statement.executeQuery("show timeseries where 'tag3'='newV3'");
+      count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertEquals(ret3[count], ans);
+          count++;
+        }
+        assertEquals(ret3.length, count);
+
+        resultSet = statement.executeQuery("show timeseries where 'tag3'='v3'");
+        assertFalse(resultSet.next());
+      } finally {
+        resultSet.close();
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java
new file mode 100644
index 0000000000..e82216c40f
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBTagIT.java
@@ -0,0 +1,1153 @@
+/*
+ * 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.it.schema;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBTagIT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initBeforeTest();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterTest();
+  }
+
+  @Test
+  public void createOneTimeseriesTest() {
+    List<String> ret =
+        Collections.singletonList(
+            "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}");
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') "
+            + "attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void createMultiTimeseriesTest() {
+    List<String> ret =
+        Arrays.asList(
+            "root.turbine.d2.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"tag1\":\"t1\","
+                + "\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
+            "root.turbine.d2.s2,status,root.turbine,INT32,RLE,SNAPPY,{\"tag2\":\"t2\","
+                + "\"tag3\":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
+    String sql1 =
+        "create timeseries root.turbine.d2.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d2.s2(status) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      statement.execute(sql2);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void showTimeseriesTest() {
+    List<String> ret =
+        Arrays.asList(
+            "root.turbine.d2.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"tag1\":\"t1\",\""
+                + "tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
+            "root.turbine.d2.s2,status,root.turbine,INT32,RLE,SNAPPY,{\"tag2\":\"t2\",\"tag3\""
+                + ":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
+    String sql1 =
+        "create timeseries root.turbine.d2.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d2.s2(status) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      statement.execute(sql2);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      int count = 0;
+      try {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      } finally {
+        resultSet.close();
+      }
+      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void createDuplicateAliasTimeseriesTest1() {
+    String sql1 =
+        "create timeseries root.turbine.d3.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d3.s2(temperature) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      try {
+        statement.execute(sql2);
+        fail();
+      } catch (Exception e) {
+        assertTrue(
+            e.getMessage()
+                .contains("Alias [temperature] for Path [root.turbine.d3.s2] already exist"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void createDuplicateAliasTimeseriesTest2() {
+    String sql1 =
+        "create timeseries root.turbine.d4.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d4.temperature with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      try {
+        statement.execute(sql2);
+        fail();
+      } catch (Exception e) {
+        assertTrue(e.getMessage().contains("Path [root.turbine.d4.temperature] already exist"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void createDuplicateAliasTimeseriesTest3() {
+    String sql1 =
+        "create timeseries root.turbine.d5.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d5.s2(s1) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      try {
+        statement.execute(sql2);
+        fail();
+      } catch (Exception e) {
+        assertTrue(
+            e.getMessage().contains("Alias [s1] for Path [root.turbine.d5.s2] already exist"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithAliasTest() {
+    List<String> ret =
+        Collections.singletonList(
+            "root.turbine.d6.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}");
+    String sql =
+        "create timeseries root.turbine.d6.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') "
+            + "attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      int count = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery("show timeseries root.turbine.d6.temperature")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithLimitTest() {
+    List<String> ret =
+        Arrays.asList(
+            "root.turbine.d1.s2,temperature2,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}",
+            "root.turbine.d1.s3,temperature3,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}");
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "create timeseries root.turbine.d1.s1(temperature1) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+              + "tags('tag1'='v1', 'tag2'='v2') "
+              + "attributes('attr1'='v1', 'attr2'='v2')");
+      statement.execute(
+          "create timeseries root.turbine.d1.s2(temperature2) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+              + "tags('tag1'='v1', 'tag2'='v2') "
+              + "attributes('attr1'='v1', 'attr2'='v2')");
+      statement.execute(
+          "create timeseries root.turbine.d1.s3(temperature3) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+              + "tags('tag1'='v1', 'tag2'='v2') "
+              + "attributes('attr1'='v1', 'attr2'='v2')");
+      int count = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery(
+              "show timeseries root.turbine.d1.** where 'tag1'='v1' limit 2 offset 1")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Ignore
+  @Test
+  public void deleteTest() {
+    List<String> ret1 =
+        Arrays.asList(
+            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
+            "root.turbine.d7.s2,status,root.turbine,INT32,RLE,SNAPPY,{\"tag2\""
+                + ":\"t2\",\"tag3\":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
+    List<String> ret2 =
+        Collections.singletonList(
+            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}");
+
+    String sql1 =
+        "create timeseries root.turbine.d7.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d7.s2(status) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      statement.execute(sql2);
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret1.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret1.size(), count);
+
+      statement.execute("delete timeseries root.turbine.d7.s2");
+      count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret2.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret2.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Ignore
+  @Test
+  public void deleteWithAliasTest() {
+    List<String> ret1 =
+        Arrays.asList(
+            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}",
+            "root.turbine.d7.s2,status,root.turbine,INT32,RLE,SNAPPY,"
+                + "{\"tag2\":\"t2\",\"tag3\":\"t3\"},{\"attr4\":\"a4\",\"attr3\":\"a3\"}");
+    List<String> ret2 =
+        Collections.singletonList(
+            "root.turbine.d7.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"t1\",\"tag2\":\"t2\"},{\"attr2\":\"a2\",\"attr1\":\"a1\"}");
+
+    String sql1 =
+        "create timeseries root.turbine.d7.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='t1', 'tag2'='t2') "
+            + "attributes('attr1'='a1', 'attr2'='a2')";
+    String sql2 =
+        "create timeseries root.turbine.d7.s2(status) with datatype=INT32, encoding=RLE "
+            + "tags('tag2'='t2', 'tag3'='t3') "
+            + "attributes('attr3'='a3', 'attr4'='a4')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql1);
+      statement.execute(sql2);
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret1.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret1.size(), count);
+
+      statement.execute("delete timeseries root.turbine.d7.status");
+      count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret2.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret2.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithWhereTest1() {
+    List<String> ret1 =
+        Arrays.asList(
+            "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+                + "this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}",
+            "root.turbine.d0.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a test2\",\"unit\":\"kw\"},{\"H_Alarm\":\"99.9\",\"M_Alarm\":\"44.4\"}",
+            "root.turbine.d1.s0,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine this "
+                + "is a test3\"},{\"H_Alarm\":\"9\",\"M_Alarm\":\"5\"}",
+            "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+                + "d2 this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}",
+            "root.turbine.d2.s1,power,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine d2 this"
+                + " is a test2\",\"unit\":\"kw\"},{\"MinValue\":\"44.4\",\"MaxValue\":\"99.9\"}",
+            "root.turbine.d2.s3,status,root.turbine,INT32,RLE,SNAPPY,{\"description\":\"turbine d2 "
+                + "this is a test3\"},{\"MinValue\":\"5\",\"MaxValue\":\"9\"}",
+            "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a "
+                + "test1\",\"unit\":\"c\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}",
+            "root.ln.d0.s1,power,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this is a "
+                + "test2\",\"unit\":\"w\"},{\"H_Alarm\":\"9.9\",\"M_Alarm\":\"4.4\"}",
+            "root.ln.d1.s0,status,root.ln,INT32,RLE,SNAPPY,{\"description\":\"ln this is a test3\"},"
+                + "{\"H_Alarm\":\"90\",\"M_Alarm\":\"50\"}");
+
+    Set<String> ret2 = new HashSet<>();
+    ret2.add(
+        "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+            + "d2 this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}");
+    ret2.add(
+        "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\""
+            + "turbine this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}");
+
+    String[] sqls = {
+      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine this is a test1') "
+          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine this is a test2') "
+          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine this is a test3') "
+          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+          + "attributes('MaxValue'='100', 'MinValue'='1')",
+      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine d2 this is a test3') "
+          + "attributes('MaxValue'='9', 'MinValue'='5')",
+      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='c', 'description'='ln this is a test1') "
+          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='w', 'description'='ln this is a test2') "
+          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='ln this is a test3') "
+          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          assertTrue(ret1.contains(ans));
+          count++;
+        }
+        assertEquals(ret1.size(), count);
+      }
+
+      count = 0;
+      Set<String> res = new HashSet<>();
+      try (ResultSet resultSet = statement.executeQuery("show timeseries where 'unit'='f'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          res.add(ans);
+          count++;
+        }
+        assertEquals(ret2, res);
+        assertEquals(ret2.size(), count);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithWhereTest2() {
+    Set<String> ret = new HashSet<>();
+    ret.add(
+        "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+            + "d2 this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}");
+    ret.add(
+        "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+            + "this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}");
+
+    String[] sqls = {
+      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine this is a test1') "
+          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine this is a test2') "
+          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine this is a test3') "
+          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+          + "attributes('MaxValue'='100', 'MinValue'='1')",
+      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine d2 this is a test3') "
+          + "attributes('MaxValue'='9', 'MinValue'='5')",
+      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='ln this is a test1') "
+          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='w', 'description'='ln this is a test2') "
+          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='ln this is a test3') "
+          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+
+      // with *
+      int count = 0;
+      Set<String> res = new HashSet<>();
+      try (ResultSet resultSet =
+          statement.executeQuery("show timeseries root.turbine.** where 'unit'='f'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          res.add(ans);
+          count++;
+        }
+      }
+      assertEquals(ret, res);
+      assertEquals(ret.size(), count);
+
+      // no *
+      count = 0;
+      res.clear();
+      try (ResultSet resultSet =
+          statement.executeQuery("show timeseries root.turbine.** where 'unit'='f'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          res.add(ans);
+          count++;
+        }
+        assertEquals(ret, res);
+        assertEquals(ret.size(), count);
+      }
+
+      count = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery("show timeseries root.turbine where 'unit'='c'")) {
+        while (resultSet.next()) {
+          count++;
+        }
+        assertEquals(0, count);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Ignore
+  @Test
+  public void queryWithWhereAndDeleteTest() {
+    Set<String> ret = new HashSet<>();
+    ret.add(
+        "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\""
+            + "turbine this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}");
+    ret.add(
+        "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this "
+            + "is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}");
+
+    String[] sqls = {
+      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine this is a test1') "
+          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine this is a test2') "
+          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine this is a test3') "
+          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+          + "attributes('MaxValue'='100', 'MinValue'='1')",
+      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine d2 this is a test3') "
+          + "attributes('MaxValue'='9', 'MinValue'='5')",
+      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='ln this is a test1') "
+          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='w', 'description'='ln this is a test2') "
+          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='ln this is a test3') "
+          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+
+      statement.execute("delete timeseries root.turbine.d2.s0");
+
+      // with *;
+      int count = 0;
+      Set<String> res = new HashSet<>();
+      try (ResultSet resultSet = statement.executeQuery("show timeseries where 'unit'='f'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          res.add(ans);
+          count++;
+        }
+      }
+      assertEquals(ret, res);
+      assertEquals(ret.size(), count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithWhereContainsTest() {
+    Set<String> ret = new HashSet<>();
+    ret.add(
+        "root.turbine.d2.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+            + "d2 this is a test1\",\"unit\":\"f\"},{\"MinValue\":\"1\",\"MaxValue\":\"100\"}");
+    ret.add(
+        "root.turbine.d0.s0,temperature,root.turbine,FLOAT,RLE,SNAPPY,{\"description\":\"turbine "
+            + "this is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"100\",\"M_Alarm\":\"50\"}");
+    ret.add(
+        "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this "
+            + "is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}");
+
+    Set<String> ret2 = new HashSet<>();
+    ret2.add(
+        "root.ln.d0.s0,temperature,root.ln,FLOAT,RLE,SNAPPY,{\"description\":\"ln this"
+            + " is a test1\",\"unit\":\"f\"},{\"H_Alarm\":\"1000\",\"M_Alarm\":\"500\"}");
+
+    String[] sqls = {
+      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine this is a test1') "
+          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine this is a test2') "
+          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine this is a test3') "
+          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+          + "attributes('MaxValue'='100', 'MinValue'='1')",
+      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine d2 this is a test3') "
+          + "attributes('MaxValue'='9', 'MinValue'='5')",
+      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='ln this is a test1') "
+          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='w', 'description'='ln this is a test2') "
+          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='ln this is a test3') "
+          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+
+      int count = 0;
+      Set<String> res = new HashSet<>();
+      try (ResultSet resultSet =
+          statement.executeQuery("show timeseries where 'description' contains 'test1'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          System.out.println(ans);
+          res.add(ans);
+          count++;
+        }
+      }
+      assertEquals(ret, res);
+      assertEquals(ret.size(), count);
+
+      count = 0;
+      res.clear();
+      try (ResultSet resultSet =
+          statement.executeQuery(
+              "show timeseries root.ln.** where 'description' contains 'test1'")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+
+          res.add(ans);
+          count++;
+        }
+      }
+      assertEquals(ret2, res);
+      assertEquals(ret2.size(), count);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void queryWithWhereOnNoneTagTest() {
+    String[] sqls = {
+      "create timeseries root.turbine.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine this is a test1') "
+          + "attributes('H_Alarm'='100', 'M_Alarm'='50')",
+      "create timeseries root.turbine.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine this is a test2') "
+          + "attributes('H_Alarm'='99.9', 'M_Alarm'='44.4')",
+      "create timeseries root.turbine.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine this is a test3') "
+          + "attributes('H_Alarm'='9', 'M_Alarm'='5')",
+      "create timeseries root.turbine.d2.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='f', 'description'='turbine d2 this is a test1') "
+          + "attributes('MaxValue'='100', 'MinValue'='1')",
+      "create timeseries root.turbine.d2.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='kw', 'description'='turbine d2 this is a test2') "
+          + "attributes('MaxValue'='99.9', 'MinValue'='44.4')",
+      "create timeseries root.turbine.d2.s3(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='turbine d2 this is a test3') "
+          + "attributes('MaxValue'='9', 'MinValue'='5')",
+      "create timeseries root.ln.d0.s0(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='c', 'description'='ln this is a test1') "
+          + "attributes('H_Alarm'='1000', 'M_Alarm'='500')",
+      "create timeseries root.ln.d0.s1(power) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+          + "tags('unit'='w', 'description'='ln this is a test2') "
+          + "attributes('H_Alarm'='9.9', 'M_Alarm'='4.4')",
+      "create timeseries root.ln.d1.s0(status) with datatype=INT32, encoding=RLE "
+          + "tags('description'='ln this is a test3') "
+          + "attributes('H_Alarm'='90', 'M_Alarm'='50')",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+
+      try (ResultSet rs = statement.executeQuery("show timeseries where 'H_Alarm'='90'")) {
+        assertFalse(rs.next());
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void sameNameTest() {
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') "
+            + "attributes('tag1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      fail();
+    } catch (Exception e) {
+      assertTrue(e.getMessage().contains("Tag and attribute shouldn't have the same property key"));
+    }
+  }
+
+  @Test
+  public void deleteStorageGroupTest() {
+    List<String> ret =
+        Collections.singletonList(
+            "root.turbine.d1.s1,temperature,root.turbine,FLOAT,RLE,SNAPPY,"
+                + "{\"tag1\":\"v1\",\"tag2\":\"v2\"},{\"attr2\":\"v2\",\"attr1\":\"v1\"}");
+
+    String sql =
+        "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY "
+            + "tags('tag1'='v1', 'tag2'='v2') "
+            + "attributes('attr1'='v1', 'attr2'='v2')";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(sql);
+      int count = 0;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString("timeseries")
+                  + ","
+                  + resultSet.getString("alias")
+                  + ","
+                  + resultSet.getString("storage group")
+                  + ","
+                  + resultSet.getString("dataType")
+                  + ","
+                  + resultSet.getString("encoding")
+                  + ","
+                  + resultSet.getString("compression")
+                  + ","
+                  + resultSet.getString("tags")
+                  + ","
+                  + resultSet.getString("attributes");
+          assertTrue(ret.contains(ans));
+          count++;
+        }
+      }
+      assertEquals(ret.size(), count);
+
+      statement.execute("delete storage group root.turbine");
+      try (ResultSet rs = statement.executeQuery("show timeseries where 'tag1'='v1'")) {
+        assertFalse(rs.next());
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void insertWithAliasTest() {
+    List<String> ret = Collections.singletonList("1,36.5,36.5");
+    String[] sqls = {
+      "create timeseries root.turbine.d1.s1(temperature) with datatype=FLOAT, encoding=RLE, compression=SNAPPY",
+      "insert into root.turbine.d1(timestamp, temperature) values(1,36.5)"
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+      boolean hasResult = statement.execute("select s1, temperature from root.turbine.d1");
+      assertTrue(hasResult);
+      // FIXME should use the same reader for measurement and its alias
+
+      //      ResultSet resultSet = statement.getResultSet();
+      //      int count = 0;
+      //      try {
+      //        while (resultSet.next()) {
+      //          String ans =
+      //              resultSet.getString("Time")
+      //                  + ","
+      //                  + resultSet.getString("root.turbine.d1.s1")
+      //                  + ","
+      //                  + resultSet.getString("root.turbine.d1.s1");
+      //          assertTrue(ret.contains(ans));
+      //          count++;
+      //        }
+      //      } finally {
+      //        resultSet.close();
+      //      }
+      //      assertEquals(ret.size(), count);
+    } catch (Exception e) {
+      e.printStackTrace();
+      assertEquals(
+          "411: Error occurred in query process: Query for measurement and its alias at the same time!",
+          e.getMessage());
+    }
+  }
+}
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java
index 849e30adda..4c2e5651d4 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBCreateStorageGroupIT.java
@@ -112,7 +112,7 @@ public class IoTDBCreateStorageGroupIT {
     try {
       statement.execute(String.format("create storage group %s", storageGroup));
     } catch (SQLException e) {
-      Assert.assertEquals(e.getMessage(), "300: root.sg has already been set to storage group");
+      Assert.assertEquals(e.getMessage(), "903: root.sg has already been set to storage group");
     }
   }
 
@@ -125,7 +125,7 @@ public class IoTDBCreateStorageGroupIT {
     try {
       statement.execute("create storage group root.sg.`device`");
     } catch (SQLException e) {
-      Assert.assertEquals(e.getMessage(), "300: root.sg has already been set to storage group");
+      Assert.assertEquals(e.getMessage(), "903: root.sg has already been set to storage group");
     }
   }
 }
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java
index a05c920524..64debcd50b 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBDeletionIT.java
@@ -91,11 +91,11 @@ public class IoTDBDeletionIT {
       statement.execute("insert into root.vehicle.d0(time,s4) values (10,true)");
 
       String errorMsg =
-          "303: Check metadata error: For delete statement, where clause can only"
+          "416: For delete statement, where clause can only"
               + " contain time expressions, value filter is not currently supported.";
 
       String errorMsg2 =
-          "303: Check metadata error: For delete statement, where clause can only contain"
+          "416: For delete statement, where clause can only contain"
               + " atomic expressions like : time > XXX, time <= XXX,"
               + " or two atomic expressions connected by 'AND'";
 
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java
index c22071994d..b9474d546a 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/aligned/IoTDBDeletionIT.java
@@ -85,11 +85,11 @@ public class IoTDBDeletionIT {
       statement.execute("insert into root.vehicle.d0(time,s4) aligned values (10,true)");
 
       String errorMsg =
-          "303: Check metadata error: For delete statement, where clause can only"
+          "416: For delete statement, where clause can only"
               + " contain time expressions, value filter is not currently supported.";
 
       String errorMsg2 =
-          "303: Check metadata error: For delete statement, where clause can only contain"
+          "416: For delete statement, where clause can only contain"
               + " atomic expressions like : time > XXX, time <= XXX,"
               + " or two atomic expressions connected by 'AND'";
 
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
index 6337e9e7f1..72406ea7f9 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
@@ -502,8 +502,8 @@ public class StorageEngineV2 implements IService {
   }
 
   /** Write data into DataRegion. For standalone mode only. */
-  public void write(DataRegionId groupId, PlanNode planNode) {
-    planNode.accept(new DataExecutionVisitor(), dataRegionMap.get(groupId));
+  public TSStatus write(DataRegionId groupId, PlanNode planNode) {
+    return planNode.accept(new DataExecutionVisitor(), dataRegionMap.get(groupId));
   }
 
   /** This function is just for unit test. */
diff --git a/server/src/main/java/org/apache/iotdb/db/exception/metadata/StorageGroupAlreadySetException.java b/server/src/main/java/org/apache/iotdb/db/exception/metadata/StorageGroupAlreadySetException.java
index f52b634e1e..19be4c077d 100644
--- a/server/src/main/java/org/apache/iotdb/db/exception/metadata/StorageGroupAlreadySetException.java
+++ b/server/src/main/java/org/apache/iotdb/db/exception/metadata/StorageGroupAlreadySetException.java
@@ -31,13 +31,13 @@ public class StorageGroupAlreadySetException extends MetadataException {
   private final String storageGroupPath;
 
   public StorageGroupAlreadySetException(String path) {
-    super(getMessage(path, false), TSStatusCode.PATH_ALREADY_EXIST_ERROR.getStatusCode());
+    super(getMessage(path, false), TSStatusCode.STORAGE_GROUP_ALREADY_EXISTS.getStatusCode());
     storageGroupPath = path;
     hasChild = false;
   }
 
   public StorageGroupAlreadySetException(String path, boolean hasChild) {
-    super(getMessage(path, hasChild), TSStatusCode.PATH_ALREADY_EXIST_ERROR.getStatusCode());
+    super(getMessage(path, hasChild), TSStatusCode.STORAGE_GROUP_ALREADY_EXISTS.getStatusCode());
     this.hasChild = hasChild;
     storageGroupPath = path;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/exception/mpp/FragmentInstanceDispatchException.java b/server/src/main/java/org/apache/iotdb/db/exception/mpp/FragmentInstanceDispatchException.java
index 8f32997d6f..d9e760e728 100644
--- a/server/src/main/java/org/apache/iotdb/db/exception/mpp/FragmentInstanceDispatchException.java
+++ b/server/src/main/java/org/apache/iotdb/db/exception/mpp/FragmentInstanceDispatchException.java
@@ -19,8 +19,21 @@
 
 package org.apache.iotdb.db.exception.mpp;
 
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+
 public class FragmentInstanceDispatchException extends Exception {
+
+  private TSStatus failureStatus;
+
   public FragmentInstanceDispatchException(Throwable t) {
     super(t);
   }
+
+  public FragmentInstanceDispatchException(TSStatus failureStatus) {
+    this.failureStatus = failureStatus;
+  }
+
+  public TSStatus getFailureStatus() {
+    return failureStatus;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaEngine.java b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaEngine.java
index 584f7b78b3..f92497cb56 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaEngine.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/schemaregion/SchemaEngine.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.metadata.schemaregion;
 
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.concurrent.IoTDBThreadPoolFactory;
 import org.apache.iotdb.commons.concurrent.threadpool.ScheduledExecutorUtil;
 import org.apache.iotdb.commons.consensus.SchemaRegionId;
@@ -68,8 +69,8 @@ public class SchemaEngine {
 
   private ScheduledExecutorService timedForceMLogThread;
 
-  public void write(SchemaRegionId schemaRegionId, PlanNode planNode) {
-    planNode.accept(new SchemaExecutionVisitor(), schemaRegionMap.get(schemaRegionId));
+  public TSStatus write(SchemaRegionId schemaRegionId, PlanNode planNode) {
+    return planNode.accept(new SchemaExecutionVisitor(), schemaRegionMap.get(schemaRegionId));
   }
 
   private static class SchemaEngineManagerHolder {
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java b/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
index 58ec1975d1..6060d77eda 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/visitor/SchemaExecutionVisitor.java
@@ -65,7 +65,7 @@ public class SchemaExecutionVisitor extends PlanVisitor<TSStatus, ISchemaRegion>
       schemaRegion.createTimeseries((CreateTimeSeriesPlan) plan, -1);
     } catch (MetadataException e) {
       logger.error("{}: MetaData error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
-      return RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage());
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
     }
     return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully");
   }
@@ -78,7 +78,7 @@ public class SchemaExecutionVisitor extends PlanVisitor<TSStatus, ISchemaRegion>
       schemaRegion.createAlignedTimeSeries((CreateAlignedTimeSeriesPlan) plan);
     } catch (MetadataException e) {
       logger.error("{}: MetaData error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
-      return RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage());
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
     }
     return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully");
   }
@@ -275,7 +275,7 @@ public class SchemaExecutionVisitor extends PlanVisitor<TSStatus, ISchemaRegion>
       }
     } catch (MetadataException e) {
       logger.error("{}: MetaData error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
-      return RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage());
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
     } catch (IOException e) {
       logger.error("{}: IO error: ", IoTDBConstant.GLOBAL_DB_NAME, e);
       return RpcUtils.getStatus(TSStatusCode.INTERNAL_SERVER_ERROR, e.getMessage());
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/QueryStateMachine.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/QueryStateMachine.java
index 0707a58033..801a1d3df2 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/QueryStateMachine.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/QueryStateMachine.java
@@ -18,6 +18,7 @@
  */
 package org.apache.iotdb.db.mpp.execution;
 
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.db.mpp.common.FragmentInstanceId;
 import org.apache.iotdb.db.mpp.common.QueryId;
 import org.apache.iotdb.db.mpp.execution.fragment.FragmentInstanceState;
@@ -41,6 +42,7 @@ public class QueryStateMachine {
   // The executor will be used in all the state machines belonged to this query.
   private Executor stateMachineExecutor;
   private Throwable failureException;
+  private TSStatus failureStatus;
 
   public QueryStateMachine(QueryId queryId, ExecutorService executor) {
     this.name = String.format("QueryStateMachine[%s]", queryId);
@@ -131,10 +133,22 @@ public class QueryStateMachine {
     queryState.set(QueryState.FAILED);
   }
 
+  public void transitionToFailed(TSStatus failureStatus) {
+    if (queryState.get().isDone()) {
+      return;
+    }
+    this.failureStatus = failureStatus;
+    queryState.set(QueryState.FAILED);
+  }
+
   public String getFailureMessage() {
     if (failureException != null) {
       return failureException.getMessage();
     }
     return "no detailed failure reason in QueryStateMachine";
   }
+
+  public TSStatus getFailureStatus() {
+    return failureStatus;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodeManageMemoryMergeOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodeManageMemoryMergeOperator.java
index 22c1d61d92..255cd0c4b5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodeManageMemoryMergeOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodeManageMemoryMergeOperator.java
@@ -38,12 +38,14 @@ public class NodeManageMemoryMergeOperator implements ProcessOperator {
   private final OperatorContext operatorContext;
   private final Set<String> data;
   private final Operator child;
+  private boolean isReadingMemory;
 
   public NodeManageMemoryMergeOperator(
       OperatorContext operatorContext, Set<String> data, Operator child) {
     this.operatorContext = requireNonNull(operatorContext, "operatorContext is null");
     this.data = data;
     this.child = requireNonNull(child, "child operator is null");
+    isReadingMemory = true;
   }
 
   @Override
@@ -53,18 +55,36 @@ public class NodeManageMemoryMergeOperator implements ProcessOperator {
 
   @Override
   public ListenableFuture<?> isBlocked() {
-    return child.isBlocked();
+    return isReadingMemory ? NOT_BLOCKED : child.isBlocked();
   }
 
   @Override
   public TsBlock next() {
-    TsBlock block = child.next();
+    if (isReadingMemory) {
+      isReadingMemory = false;
+      return transferToTsBlock(data);
+    } else {
+      TsBlock block = child.next();
+      if (block == null) {
+        return null;
+      }
+
+      Set<String> nodePaths = new TreeSet<>();
+      String nodePath;
+      for (int i = 0; i < block.getPositionCount(); i++) {
+        nodePath = block.getColumn(0).getBinary(i).toString();
+        if (!data.contains(nodePath)) {
+          nodePaths.add(nodePath);
+          data.add(nodePath);
+        }
+      }
+      return transferToTsBlock(nodePaths);
+    }
+  }
+
+  private TsBlock transferToTsBlock(Set<String> nodePaths) {
     TsBlockBuilder tsBlockBuilder =
         new TsBlockBuilder(HeaderConstant.showChildPathsHeader.getRespDataTypes());
-    Set<String> nodePaths = new TreeSet<>(data);
-    for (int i = 0; i < block.getPositionCount(); i++) {
-      nodePaths.add(block.getColumn(0).getBinary(i).toString());
-    }
 
     nodePaths.forEach(
         path -> {
@@ -77,7 +97,7 @@ public class NodeManageMemoryMergeOperator implements ProcessOperator {
 
   @Override
   public boolean hasNext() {
-    return child.hasNext();
+    return isReadingMemory || child.hasNext();
   }
 
   @Override
@@ -87,6 +107,6 @@ public class NodeManageMemoryMergeOperator implements ProcessOperator {
 
   @Override
   public boolean isFinished() {
-    return child.isFinished();
+    return !isReadingMemory && child.isFinished();
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsCountOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsCountOperator.java
index ca8f8ef5da..98df95be4a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsCountOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsCountOperator.java
@@ -71,19 +71,20 @@ public class NodePathsCountOperator implements ProcessOperator {
 
   @Override
   public ListenableFuture<?> isBlocked() {
-    ListenableFuture<?> blocked = child.isBlocked();
-    while (child.hasNext() && blocked.isDone()) {
-      TsBlock tsBlock = child.next();
-      if (null != tsBlock && !tsBlock.isEmpty()) {
-        for (int i = 0; i < tsBlock.getPositionCount(); i++) {
-          String path = tsBlock.getColumn(0).getBinary(i).toString();
-          nodePaths.add(path);
+    while (!child.isFinished()) {
+      ListenableFuture<?> blocked = child.isBlocked();
+      if (!blocked.isDone()) {
+        return blocked;
+      }
+      if (child.hasNext()) {
+        TsBlock tsBlock = child.next();
+        if (null != tsBlock && !tsBlock.isEmpty()) {
+          for (int i = 0; i < tsBlock.getPositionCount(); i++) {
+            String path = tsBlock.getColumn(0).getBinary(i).toString();
+            nodePaths.add(path);
+          }
         }
       }
-      blocked = child.isBlocked();
-    }
-    if (!blocked.isDone()) {
-      return blocked;
     }
     return NOT_BLOCKED;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsSchemaScanOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsSchemaScanOperator.java
index a35dff908b..374368aae5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsSchemaScanOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/NodePathsSchemaScanOperator.java
@@ -74,7 +74,8 @@ public class NodePathsSchemaScanOperator implements SourceOperator {
       } else {
         nodePaths =
             ((SchemaDriverContext) operatorContext.getInstanceContext().getDriverContext())
-                .getSchemaRegion().getNodesListInGivenLevel(partialPath, level, true, null).stream()
+                .getSchemaRegion().getNodesListInGivenLevel(partialPath, level, false, null)
+                    .stream()
                     .map(PartialPath::getFullPath)
                     .collect(Collectors.toSet());
       }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaFetchMergeOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaFetchMergeOperator.java
index 57ea220b63..31575a5be9 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaFetchMergeOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaFetchMergeOperator.java
@@ -65,7 +65,7 @@ public class SchemaFetchMergeOperator implements ProcessOperator {
 
   @Override
   public ListenableFuture<?> isBlocked() {
-    return children.get(currentIndex).isBlocked();
+    return currentIndex < children.size() ? children.get(currentIndex).isBlocked() : NOT_BLOCKED;
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryMergeOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryMergeOperator.java
index 87df583494..519cdce27e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryMergeOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryMergeOperator.java
@@ -66,7 +66,7 @@ public class SchemaQueryMergeOperator implements ProcessOperator {
 
   @Override
   public ListenableFuture<?> isBlocked() {
-    return children.get(currentIndex).isBlocked();
+    return currentIndex < children.size() ? children.get(currentIndex).isBlocked() : NOT_BLOCKED;
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryOrderByHeatOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryOrderByHeatOperator.java
index 7bb06a3114..5b65e10cc8 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryOrderByHeatOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryOrderByHeatOperator.java
@@ -42,16 +42,18 @@ public class SchemaQueryOrderByHeatOperator implements ProcessOperator {
   private final OperatorContext operatorContext;
   private boolean isFinished = false;
   private final List<Operator> operators;
-  private final boolean[] noMoreTsBlocks;
   private final List<TsBlock> showTimeSeriesResult;
   private final List<TsBlock> lastQueryResult;
 
+  private int currentIndex;
+
   public SchemaQueryOrderByHeatOperator(OperatorContext operatorContext, List<Operator> operators) {
     this.operatorContext = requireNonNull(operatorContext, "operatorContext is null");
     this.operators = operators;
-    this.noMoreTsBlocks = new boolean[operators.size()];
     this.showTimeSeriesResult = new ArrayList<>();
     this.lastQueryResult = new ArrayList<>();
+
+    currentIndex = 0;
   }
 
   @Override
@@ -117,28 +119,41 @@ public class SchemaQueryOrderByHeatOperator implements ProcessOperator {
 
   @Override
   public ListenableFuture<?> isBlocked() {
-    for (int i = 0; i < operators.size(); i++) {
-      if (!noMoreTsBlocks[i]) {
-        Operator operator = operators.get(i);
-        ListenableFuture<?> blocked = operator.isBlocked();
-        while (operator.hasNext() && blocked.isDone()) {
-          TsBlock tsBlock = operator.next();
-          if (null != tsBlock && !tsBlock.isEmpty()) {
-            if (isShowTimeSeriesBlock(tsBlock)) {
-              showTimeSeriesResult.add(tsBlock);
-            } else {
-              lastQueryResult.add(tsBlock);
-            }
+    Operator operator;
+    ListenableFuture<?> blocked;
+    while (currentIndex < operators.size()) {
+      operator = operators.get(currentIndex);
+      blocked = readCurrentChild(operator);
+      if (blocked != null) {
+        // not null means blocked
+        return blocked;
+      } else {
+        // null means current operator is finished
+        currentIndex++;
+      }
+    }
+
+    return NOT_BLOCKED;
+  }
+
+  private ListenableFuture<?> readCurrentChild(Operator operator) {
+    while (!operator.isFinished()) {
+      ListenableFuture<?> blocked = operator.isBlocked();
+      if (!blocked.isDone()) {
+        return blocked;
+      }
+      if (operator.hasNext()) {
+        TsBlock tsBlock = operator.next();
+        if (null != tsBlock && !tsBlock.isEmpty()) {
+          if (isShowTimeSeriesBlock(tsBlock)) {
+            showTimeSeriesResult.add(tsBlock);
+          } else {
+            lastQueryResult.add(tsBlock);
           }
-          blocked = operator.isBlocked();
-        }
-        if (!blocked.isDone()) {
-          return blocked;
         }
-        noMoreTsBlocks[i] = true;
       }
     }
-    return NOT_BLOCKED;
+    return null;
   }
 
   private boolean isShowTimeSeriesBlock(TsBlock tsBlock) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesSchemaScanOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesSchemaScanOperator.java
index dfb9cf177f..e3b63183da 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesSchemaScanOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/schema/TimeSeriesSchemaScanOperator.java
@@ -93,7 +93,7 @@ public class TimeSeriesSchemaScanOperator extends SchemaQueryScanOperator {
 
   // ToDo @xinzhongtianxia remove this temporary converter after mpp online
   private ShowTimeSeriesPlan convertToPhysicalPlan() {
-    return new ShowTimeSeriesPlan(partialPath, isContains, key, value, limit, offset, orderByHeat);
+    return new ShowTimeSeriesPlan(partialPath, isContains, key, value, limit, offset, false);
   }
 
   private void setColumns(ShowTimeSeriesResult series, TsBlockBuilder builder) {
@@ -118,8 +118,14 @@ public class TimeSeriesSchemaScanOperator extends SchemaQueryScanOperator {
   }
 
   private String mapToString(Map<String, String> map) {
-    return map.entrySet().stream()
-        .map(e -> "\"" + e.getKey() + "\"" + ":" + "\"" + e.getValue() + "\"")
-        .collect(Collectors.joining(","));
+    String content =
+        map.entrySet().stream()
+            .map(e -> "\"" + e.getKey() + "\"" + ":" + "\"" + e.getValue() + "\"")
+            .collect(Collectors.joining(","));
+    if (content.isEmpty()) {
+      return "null";
+    } else {
+      return "{" + content + "}";
+    }
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
index 0a4aeccfac..2af7e16daa 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
@@ -1458,6 +1458,10 @@ public class Analyzer {
       DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
       analysis.setDataPartitionInfo(dataPartition);
 
+      if (dataPartition.isEmpty()) {
+        analysis.setFinishQueryAfterAnalyze(true);
+      }
+
       return analysis;
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/StandalonePartitionFetcher.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/StandalonePartitionFetcher.java
index 33f35d006c..59bd18ec6f 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/StandalonePartitionFetcher.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/StandalonePartitionFetcher.java
@@ -35,6 +35,7 @@ import org.apache.iotdb.db.localconfignode.LocalConfigNode;
 import org.apache.iotdb.db.metadata.utils.MetaUtils;
 import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq;
+import org.apache.iotdb.tsfile.utils.Pair;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -45,6 +46,9 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
 
 public class StandalonePartitionFetcher implements IPartitionFetcher {
 
@@ -88,7 +92,41 @@ public class StandalonePartitionFetcher implements IPartitionFetcher {
   @Override
   public SchemaNodeManagementPartition getSchemaNodeManagementPartitionWithLevel(
       PathPatternTree patternTree, Integer level) {
-    return null;
+    try {
+      patternTree.constructTree();
+      Set<String> matchedNodes = new HashSet<>();
+      Set<PartialPath> involvedStorageGroup = new HashSet<>();
+      if (level == null) {
+        // Get Child
+        for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+          Pair<Set<String>, Set<PartialPath>> result =
+              localConfigNode.getChildNodePathInNextLevel(pathPattern);
+          matchedNodes.addAll(result.left);
+          involvedStorageGroup.addAll(result.right);
+        }
+      } else {
+        for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+          Pair<List<PartialPath>, Set<PartialPath>> result =
+              localConfigNode.getNodesListInGivenLevel(pathPattern, level, false, null);
+          matchedNodes.addAll(
+              result.left.stream().map(PartialPath::getFullPath).collect(Collectors.toList()));
+          involvedStorageGroup.addAll(result.right);
+        }
+      }
+
+      PathPatternTree partitionReq = new PathPatternTree();
+      involvedStorageGroup.forEach(
+          storageGroup ->
+              partitionReq.appendPathPattern(storageGroup.concatNode(MULTI_LEVEL_PATH_WILDCARD)));
+
+      return new SchemaNodeManagementPartition(
+          localConfigNode.getSchemaPartition(patternTree),
+          IoTDBDescriptor.getInstance().getConfig().getSeriesPartitionExecutorClass(),
+          IoTDBDescriptor.getInstance().getConfig().getSeriesPartitionSlotNum(),
+          matchedNodes);
+    } catch (MetadataException e) {
+      throw new RuntimeException(e);
+    }
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/QueryExecution.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/QueryExecution.java
index 88c17bd4d0..4bae3eeafc 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/QueryExecution.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/QueryExecution.java
@@ -401,6 +401,10 @@ public class QueryExecution implements IQueryExecution {
 
     TSStatus tsstatus = RpcUtils.getStatus(statusCode, stateMachine.getFailureMessage());
 
+    if (stateMachine.getFailureStatus() != null) {
+      tsstatus = stateMachine.getFailureStatus();
+    }
+
     // collect redirect info to client for writing
     if (analysis.getStatement() instanceof InsertBaseStatement) {
       InsertBaseStatement insertStatement = (InsertBaseStatement) analysis.getStatement();
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/memory/StatementMemorySourceVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/memory/StatementMemorySourceVisitor.java
index e2f5d6c7c0..40927caf1a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/memory/StatementMemorySourceVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/memory/StatementMemorySourceVisitor.java
@@ -20,6 +20,8 @@
 package org.apache.iotdb.db.mpp.plan.execution.memory;
 
 import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.mpp.common.header.ColumnHeader;
 import org.apache.iotdb.db.mpp.common.header.DatasetHeader;
 import org.apache.iotdb.db.mpp.common.header.HeaderConstant;
@@ -30,7 +32,9 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanGraphPrinter;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.mpp.plan.statement.StatementNode;
 import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.CountDevicesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CountNodesStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.CountTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildNodesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildPathsStatement;
 import org.apache.iotdb.db.mpp.plan.statement.sys.ExplainStatement;
@@ -106,9 +110,15 @@ public class StatementMemorySourceVisitor
     Set<String> matchedChildNodes = new TreeSet<>(context.getAnalysis().getMatchedNodes());
     matchedChildNodes.forEach(
         node -> {
-          tsBlockBuilder.getTimeColumnBuilder().writeLong(0L);
-          tsBlockBuilder.getColumnBuilder(0).writeBinary(new Binary(node));
-          tsBlockBuilder.declarePosition();
+          try {
+            PartialPath nodePath = new PartialPath(node);
+            String nodeName = nodePath.getTailNode();
+            tsBlockBuilder.getTimeColumnBuilder().writeLong(0L);
+            tsBlockBuilder.getColumnBuilder(0).writeBinary(new Binary(nodeName));
+            tsBlockBuilder.declarePosition();
+          } catch (IllegalPathException ignored) {
+            // definitely won't happen
+          }
         });
     return new StatementMemorySource(
         tsBlockBuilder.build(), context.getAnalysis().getRespDatasetHeader());
@@ -138,4 +148,28 @@ public class StatementMemorySourceVisitor
     return new StatementMemorySource(
         tsBlockBuilder.build(), context.getAnalysis().getRespDatasetHeader());
   }
+
+  @Override
+  public StatementMemorySource visitCountDevices(
+      CountDevicesStatement countStatement, StatementMemorySourceContext context) {
+    TsBlockBuilder tsBlockBuilder =
+        new TsBlockBuilder(HeaderConstant.countDevicesHeader.getRespDataTypes());
+    tsBlockBuilder.getTimeColumnBuilder().writeLong(0L);
+    tsBlockBuilder.getColumnBuilder(0).writeInt(0);
+    tsBlockBuilder.declarePosition();
+    return new StatementMemorySource(
+        tsBlockBuilder.build(), context.getAnalysis().getRespDatasetHeader());
+  }
+
+  @Override
+  public StatementMemorySource visitCountTimeSeries(
+      CountTimeSeriesStatement countStatement, StatementMemorySourceContext context) {
+    TsBlockBuilder tsBlockBuilder =
+        new TsBlockBuilder(HeaderConstant.countTimeSeriesHeader.getRespDataTypes());
+    tsBlockBuilder.getTimeColumnBuilder().writeLong(0L);
+    tsBlockBuilder.getColumnBuilder(0).writeInt(0);
+    tsBlockBuilder.declarePosition();
+    return new StatementMemorySource(
+        tsBlockBuilder.build(), context.getAnalysis().getRespDatasetHeader());
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanner.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanner.java
index f0b083aa7f..cac693ec6e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanner.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanner.java
@@ -453,11 +453,15 @@ public class LogicalPlanner {
       // source operator.
       boolean canPushDownOffsetLimit =
           analysis.getSchemaPartitionInfo() != null
-              && analysis.getSchemaPartitionInfo().getDistributionInfo().size() == 1;
+              && analysis.getSchemaPartitionInfo().getDistributionInfo().size() == 1
+              && !showTimeSeriesStatement.isOrderByHeat();
 
       int limit = showTimeSeriesStatement.getLimit();
       int offset = showTimeSeriesStatement.getOffset();
-      if (!canPushDownOffsetLimit) {
+      if (showTimeSeriesStatement.isOrderByHeat()) {
+        limit = 0;
+        offset = 0;
+      } else if (!canPushDownOffsetLimit) {
         limit = showTimeSeriesStatement.getLimit() + showTimeSeriesStatement.getOffset();
         offset = 0;
       }
@@ -484,14 +488,14 @@ public class LogicalPlanner {
         planBuilder = planBuilder.planSchemaQueryOrderByHeat(lastPlanNode);
       }
 
-      if (!canPushDownOffsetLimit) {
-        return planBuilder
-            .planOffset(showTimeSeriesStatement.getOffset())
-            .planLimit(showTimeSeriesStatement.getLimit())
-            .getRoot();
+      if (canPushDownOffsetLimit) {
+        return planBuilder.getRoot();
       }
 
-      return planBuilder.getRoot();
+      return planBuilder
+          .planOffset(showTimeSeriesStatement.getOffset())
+          .planLimit(showTimeSeriesStatement.getLimit())
+          .getRoot();
     }
 
     @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/write/DeleteDataNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/write/DeleteDataNode.java
index bc5efc0d10..ccc1bbd366 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/write/DeleteDataNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/write/DeleteDataNode.java
@@ -174,21 +174,12 @@ public class DeleteDataNode extends WritePlanNode {
     Map<TRegionReplicaSet, List<PartialPath>> regionToPatternMap = new HashMap<>();
 
     for (PartialPath pathPattern : pathList) {
-      PartialPath devicePattern = pathPattern;
-      if (!pathPattern.getTailNode().equals(MULTI_LEVEL_PATH_WILDCARD)) {
-        devicePattern = pathPattern.getDevicePath();
-      }
-      for (DeviceSchemaInfo deviceSchemaInfo : schemaTree.getMatchedDevices(devicePattern)) {
-        PartialPath devicePath = deviceSchemaInfo.getDevicePath();
-        // todo implement time slot
-        for (TRegionReplicaSet regionReplicaSet :
-            dataPartition.getDataRegionReplicaSet(
-                devicePath.getFullPath(), Collections.emptyList())) {
-          regionToPatternMap
-              .computeIfAbsent(regionReplicaSet, o -> new ArrayList<>())
-              .addAll(pathPattern.alterPrefixPath(devicePath));
-        }
+      if (pathPattern.getTailNode().equals(MULTI_LEVEL_PATH_WILDCARD)) {
+        splitPathPatternByDevice(
+            pathPattern, pathPattern, schemaTree, dataPartition, regionToPatternMap);
       }
+      splitPathPatternByDevice(
+          pathPattern.getDevicePath(), pathPattern, schemaTree, dataPartition, regionToPatternMap);
     }
 
     return regionToPatternMap.keySet().stream()
@@ -198,4 +189,23 @@ public class DeleteDataNode extends WritePlanNode {
                     getPlanNodeId(), regionToPatternMap.get(o), deleteStartTime, deleteEndTime, o))
         .collect(Collectors.toList());
   }
+
+  private void splitPathPatternByDevice(
+      PartialPath devicePattern,
+      PartialPath pathPattern,
+      SchemaTree schemaTree,
+      DataPartition dataPartition,
+      Map<TRegionReplicaSet, List<PartialPath>> regionToPatternMap) {
+    for (DeviceSchemaInfo deviceSchemaInfo : schemaTree.getMatchedDevices(devicePattern)) {
+      PartialPath devicePath = deviceSchemaInfo.getDevicePath();
+      // todo implement time slot
+      for (TRegionReplicaSet regionReplicaSet :
+          dataPartition.getDataRegionReplicaSet(
+              devicePath.getFullPath(), Collections.emptyList())) {
+        regionToPatternMap
+            .computeIfAbsent(regionReplicaSet, o -> new ArrayList<>())
+            .addAll(pathPattern.alterPrefixPath(devicePath));
+      }
+    }
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/ClusterScheduler.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/ClusterScheduler.java
index 054c2e4a51..0a6d51eb4a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/ClusterScheduler.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/ClusterScheduler.java
@@ -100,7 +100,12 @@ public class ClusterScheduler implements IScheduler {
       FragInstanceDispatchResult result = dispatchResultFuture.get();
       if (!result.isSuccessful()) {
         logger.error("dispatch failed.");
-        stateMachine.transitionToFailed(new IllegalStateException("Fragment cannot be dispatched"));
+        if (result.getFailureStatus() != null) {
+          stateMachine.transitionToFailed(result.getFailureStatus());
+        } else {
+          stateMachine.transitionToFailed(
+              new IllegalStateException("Fragment cannot be dispatched"));
+        }
         return;
       }
     } catch (InterruptedException | ExecutionException e) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragInstanceDispatchResult.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragInstanceDispatchResult.java
index b2d680ccc7..80af9c9a34 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragInstanceDispatchResult.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragInstanceDispatchResult.java
@@ -19,14 +19,27 @@
 
 package org.apache.iotdb.db.mpp.plan.scheduler;
 
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+
 public class FragInstanceDispatchResult {
   private boolean successful;
 
+  private TSStatus failureStatus;
+
   public FragInstanceDispatchResult(boolean successful) {
     this.successful = successful;
   }
 
+  public FragInstanceDispatchResult(TSStatus failureStatus) {
+    this.successful = false;
+    this.failureStatus = failureStatus;
+  }
+
   public boolean isSuccessful() {
     return successful;
   }
+
+  public TSStatus getFailureStatus() {
+    return failureStatus;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragmentInstanceDispatcherImpl.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragmentInstanceDispatcherImpl.java
index 8e21fb108e..d3f0d21e86 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragmentInstanceDispatcherImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/FragmentInstanceDispatcherImpl.java
@@ -43,6 +43,7 @@ import org.apache.iotdb.mpp.rpc.thrift.TSendFragmentInstanceReq;
 import org.apache.iotdb.mpp.rpc.thrift.TSendFragmentInstanceResp;
 import org.apache.iotdb.mpp.rpc.thrift.TSendPlanNodeReq;
 import org.apache.iotdb.mpp.rpc.thrift.TSendPlanNodeResp;
+import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import com.google.common.util.concurrent.SettableFuture;
@@ -149,7 +150,7 @@ public class FragmentInstanceDispatcherImpl implements IFragInstanceDispatcher {
       return immediateFuture(new FragInstanceDispatchResult(result));
     } catch (FragmentInstanceDispatchException e) {
       logger.error("cannot dispatch FI for write operation", e);
-      return immediateFuture(new FragInstanceDispatchResult(false));
+      return immediateFuture(new FragInstanceDispatchResult(e.getFailureStatus()));
     }
   }
 
@@ -188,7 +189,11 @@ public class FragmentInstanceDispatcherImpl implements IFragInstanceDispatcher {
                   new TPlanNode(instance.getFragment().getRoot().serializeToByteBuffer()),
                   instance.getRegionReplicaSet().getRegionId());
           TSendPlanNodeResp sendPlanNodeResp = client.sendPlanNode(sendPlanNodeReq);
-          return sendPlanNodeResp.accepted;
+          if (!sendPlanNodeResp.accepted) {
+            logger.error(sendPlanNodeResp.getStatus().message);
+            throw new FragmentInstanceDispatchException(sendPlanNodeResp.getStatus());
+          }
+          return true;
       }
     } catch (IOException | TException e) {
       logger.error("can't connect to node {}", endPoint, e);
@@ -221,6 +226,7 @@ public class FragmentInstanceDispatcherImpl implements IFragInstanceDispatcher {
       case WRITE:
         PlanNode planNode = instance.getFragment().getRoot();
         boolean hasFailedMeasurement = false;
+        String partialInsertMessage = null;
         if (planNode instanceof InsertNode) {
           InsertNode insertNode = (InsertNode) planNode;
           try {
@@ -230,10 +236,11 @@ public class FragmentInstanceDispatcherImpl implements IFragInstanceDispatcher {
           }
           hasFailedMeasurement = insertNode.hasFailedMeasurements();
           if (hasFailedMeasurement) {
-            logger.warn(
-                "Fail to insert measurements {} caused by {}",
-                insertNode.getFailedMeasurements(),
-                insertNode.getFailedMessages());
+            partialInsertMessage =
+                String.format(
+                    "Fail to insert measurements %s caused by %s",
+                    insertNode.getFailedMeasurements(), insertNode.getFailedMessages());
+            logger.warn(partialInsertMessage);
           }
         }
         ConsensusWriteResponse writeResponse;
@@ -242,8 +249,17 @@ public class FragmentInstanceDispatcherImpl implements IFragInstanceDispatcher {
         } else {
           writeResponse = SchemaRegionConsensusImpl.getInstance().write(groupId, planNode);
         }
-        return !hasFailedMeasurement
-            && TSStatusCode.SUCCESS_STATUS.getStatusCode() == writeResponse.getStatus().getCode();
+
+        if (writeResponse.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+          logger.error(writeResponse.getStatus().message);
+          throw new FragmentInstanceDispatchException(writeResponse.getStatus());
+        } else if (hasFailedMeasurement) {
+          throw new FragmentInstanceDispatchException(
+              RpcUtils.getStatus(
+                  TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
+        }
+
+        return true;
     }
     throw new UnsupportedOperationException(
         String.format("unknown query type [%s]", instance.getType()));
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/StandaloneScheduler.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/StandaloneScheduler.java
index f4b7664c57..328cbaa32f 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/StandaloneScheduler.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/scheduler/StandaloneScheduler.java
@@ -19,6 +19,7 @@
 package org.apache.iotdb.db.mpp.plan.scheduler;
 
 import org.apache.iotdb.common.rpc.thrift.TEndPoint;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.client.IClientManager;
 import org.apache.iotdb.commons.client.sync.SyncDataNodeInternalServiceClient;
 import org.apache.iotdb.commons.consensus.ConsensusGroupId;
@@ -41,6 +42,7 @@ import org.apache.iotdb.db.mpp.plan.analyze.SchemaValidator;
 import org.apache.iotdb.db.mpp.plan.planner.plan.FragmentInstance;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.mpp.plan.planner.plan.node.write.InsertNode;
+import org.apache.iotdb.rpc.TSStatusCode;
 
 import io.airlift.units.Duration;
 import org.slf4j.Logger;
@@ -155,11 +157,16 @@ public class StandaloneScheduler implements IScheduler {
                     insertNode.getFailedMessages());
               }
             }
+
+            TSStatus executionResult;
+
             if (groupId instanceof DataRegionId) {
-              STORAGE_ENGINE.write((DataRegionId) groupId, planNode);
+              executionResult = STORAGE_ENGINE.write((DataRegionId) groupId, planNode);
             } else {
-              SCHEMA_ENGINE.write((SchemaRegionId) groupId, planNode);
+              executionResult = SCHEMA_ENGINE.write((SchemaRegionId) groupId, planNode);
             }
+
+            // partial insert
             if (hasFailedMeasurement) {
               InsertNode node = (InsertNode) planNode;
               List<Exception> exceptions = node.getFailedExceptions();
@@ -170,6 +177,12 @@ public class StandaloneScheduler implements IScheduler {
                           ? (" caused by " + exceptions.get(0).getMessage())
                           : ""));
             }
+
+            if (executionResult.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+              LOGGER.error("Execute write operation error: {}", executionResult.getMessage());
+              stateMachine.transitionToFailed(executionResult);
+              return;
+            }
           }
           stateMachine.transitionToFinished();
         } catch (Exception e) {
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/meta/InfluxDBMetaManager.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/meta/InfluxDBMetaManager.java
index a331edbff4..0dd094f9da 100644
--- a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/meta/InfluxDBMetaManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/meta/InfluxDBMetaManager.java
@@ -33,6 +33,7 @@ import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.service.basic.ServiceProvider;
+import org.apache.iotdb.rpc.TSStatusCode;
 import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
 import org.apache.iotdb.tsfile.read.common.Field;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
@@ -133,7 +134,7 @@ public class InfluxDBMetaManager {
       serviceProvider.executeNonQuery(setStorageGroupPlan);
     } catch (QueryProcessException e) {
       // errCode = 300 means sg has already set
-      if (e.getErrorCode() != 300) {
+      if (e.getErrorCode() != TSStatusCode.STORAGE_GROUP_ALREADY_EXISTS.getStatusCode()) {
         throw new InfluxDBException(e.getMessage());
       }
     } catch (IllegalPathException | StorageGroupNotSetException | StorageEngineException e) {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 378646ea45..79bb5d9db0 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -1880,7 +1880,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
 
   private Pair<Long, Long> parseDeleteTimeInterval(FilterOperator filterOperator) {
     if (!filterOperator.isLeaf() && filterOperator.getFilterType() != FilterType.KW_AND) {
-      throw new SQLParserException(DELETE_RANGE_ERROR_MSG);
+      throw new SemanticException(DELETE_RANGE_ERROR_MSG);
     }
 
     if (filterOperator.isLeaf()) {
@@ -1891,7 +1891,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
     FilterOperator lOperator = children.get(0);
     FilterOperator rOperator = children.get(1);
     if (!lOperator.isLeaf() || !rOperator.isLeaf()) {
-      throw new SQLParserException(DELETE_RANGE_ERROR_MSG);
+      throw new SemanticException(DELETE_RANGE_ERROR_MSG);
     }
 
     Pair<Long, Long> leftOpInterval = calcOperatorInterval(lOperator);
@@ -3427,7 +3427,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
 
     if (filterOperator.getSinglePath() != null
         && !IoTDBConstant.TIME.equals(filterOperator.getSinglePath().getMeasurement())) {
-      throw new SQLParserException(DELETE_ONLY_SUPPORT_TIME_EXP_ERROR_MSG);
+      throw new SemanticException(DELETE_ONLY_SUPPORT_TIME_EXP_ERROR_MSG);
     }
 
     long time = Long.parseLong(((BasicFunctionOperator) filterOperator).getValue());
diff --git a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
index 4ef5e03fb2..16b04f4e7b 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/DataNodeInternalRPCServiceImpl.java
@@ -150,6 +150,7 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
 
     PlanNode planNode = PlanNodeType.deserialize(req.planNode.body);
     boolean hasFailedMeasurement = false;
+    String partialInsertMessage = null;
     if (planNode instanceof InsertNode) {
       InsertNode insertNode = (InsertNode) planNode;
       try {
@@ -161,10 +162,11 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
       }
       hasFailedMeasurement = insertNode.hasFailedMeasurements();
       if (hasFailedMeasurement) {
-        LOGGER.warn(
-            "Fail to insert measurements {} caused by {}",
-            insertNode.getFailedMeasurements(),
-            insertNode.getFailedMessages());
+        partialInsertMessage =
+            String.format(
+                "Fail to insert measurements %s caused by %s",
+                insertNode.getFailedMeasurements(), insertNode.getFailedMessages());
+        LOGGER.warn(partialInsertMessage);
       }
     }
     if (groupId instanceof DataRegionId) {
@@ -178,7 +180,16 @@ public class DataNodeInternalRPCServiceImpl implements IDataNodeRPCService.Iface
           !hasFailedMeasurement
               && TSStatusCode.SUCCESS_STATUS.getStatusCode()
                   == writeResponse.getStatus().getCode());
-      response.setMessage(writeResponse.getStatus().message);
+      if (TSStatusCode.SUCCESS_STATUS.getStatusCode() != writeResponse.getStatus().getCode()) {
+        response.setMessage(writeResponse.getStatus().message);
+        response.setStatus(writeResponse.getStatus());
+      } else if (hasFailedMeasurement) {
+        response.setMessage(partialInsertMessage);
+        response.setStatus(
+            RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
+      } else {
+        response.setMessage(writeResponse.getStatus().message);
+      }
     } else {
       LOGGER.error(
           "Something wrong happened while calling consensus layer's write API.",
diff --git a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/InfluxDBServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/InfluxDBServiceImpl.java
index 1a4197bcc5..dee86edde3 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/InfluxDBServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/InfluxDBServiceImpl.java
@@ -133,7 +133,8 @@ public class InfluxDBServiceImpl implements InfluxDBService.Iface {
         | QueryProcessException
         | StorageGroupNotSetException
         | StorageEngineException e) {
-      if (e instanceof QueryProcessException && e.getErrorCode() == 300) {
+      if (e instanceof QueryProcessException
+          && e.getErrorCode() == TSStatusCode.STORAGE_GROUP_ALREADY_EXISTS.getStatusCode()) {
         return RpcUtils.getInfluxDBStatus(
             TSStatusCode.SUCCESS_STATUS.getStatusCode(), "Execute successfully");
       }
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryScanOperatorTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryScanOperatorTest.java
index 64b240efa1..4a7d6c387a 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryScanOperatorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/schema/SchemaQueryScanOperatorTest.java
@@ -43,7 +43,6 @@ import org.apache.iotdb.tsfile.read.common.block.column.BinaryColumn;
 import org.apache.iotdb.tsfile.utils.Binary;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 
-import org.apache.commons.lang.StringUtils;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -236,7 +235,7 @@ public class SchemaQueryScanOperatorTest {
                 break;
               case 6:
               case 7:
-                assertTrue(StringUtils.isBlank(value));
+                assertEquals("null", value);
               default:
                 break;
             }
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
index 860a7b2c7e..1646afe43f 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
@@ -491,9 +491,9 @@ public class LogicalPlannerTest {
       Assert.assertFalse(showTimeSeriesNode.isContains());
       Assert.assertEquals("tagK", showTimeSeriesNode.getKey());
       Assert.assertEquals("tagV", showTimeSeriesNode.getValue());
-      Assert.assertEquals(30, showTimeSeriesNode.getLimit());
+      Assert.assertEquals(0, showTimeSeriesNode.getLimit());
       Assert.assertEquals(0, showTimeSeriesNode.getOffset());
-      Assert.assertTrue(showTimeSeriesNode.isHasLimit());
+      Assert.assertFalse(showTimeSeriesNode.isHasLimit());
 
       // test serialize and deserialize
       ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
@@ -509,9 +509,9 @@ public class LogicalPlannerTest {
       Assert.assertFalse(showTimeSeriesNode2.isContains());
       Assert.assertEquals("tagK", showTimeSeriesNode2.getKey());
       Assert.assertEquals("tagV", showTimeSeriesNode2.getValue());
-      Assert.assertEquals(30, showTimeSeriesNode2.getLimit());
+      Assert.assertEquals(0, showTimeSeriesNode2.getLimit());
       Assert.assertEquals(0, showTimeSeriesNode2.getOffset());
-      Assert.assertTrue(showTimeSeriesNode2.isHasLimit());
+      Assert.assertFalse(showTimeSeriesNode2.isHasLimit());
     } catch (Exception e) {
       e.printStackTrace();
       fail();
diff --git a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
index 1226e31628..4dbb32ec4c 100644
--- a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.exception.sql.SQLParserException;
+import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
 import org.apache.iotdb.db.qp.logical.sys.DeleteStorageGroupOperator;
@@ -306,7 +307,7 @@ public class LogicalPlanSmallTest {
     String errorMsg = null;
     try {
       LogicalGenerator.generate(sql, ZoneId.systemDefault());
-    } catch (SQLParserException e) {
+    } catch (SemanticException e) {
       errorMsg = e.getMessage();
     }
     Assert.assertEquals(
@@ -318,7 +319,7 @@ public class LogicalPlanSmallTest {
     errorMsg = null;
     try {
       LogicalGenerator.generate(sql, ZoneId.systemDefault());
-    } catch (SQLParserException e) {
+    } catch (SemanticException e) {
       errorMsg = e.getMessage();
     }
     Assert.assertEquals(
diff --git a/thrift/src/main/thrift/datanode.thrift b/thrift/src/main/thrift/datanode.thrift
index 3b515f646b..3ceeefb0c4 100644
--- a/thrift/src/main/thrift/datanode.thrift
+++ b/thrift/src/main/thrift/datanode.thrift
@@ -106,6 +106,7 @@ struct TSendPlanNodeReq {
 struct TSendPlanNodeResp {
   1: required bool accepted
   2: optional string message
+  3: optional common.TSStatus status
 }
 
 struct TFetchFragmentInstanceStateReq {