You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2019/10/29 06:42:49 UTC

[incubator-iotdb] branch master updated: [IOTDB-205]Support storage-group-level data ttl (#429)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new a89cde6  [IOTDB-205]Support storage-group-level data ttl (#429)
a89cde6 is described below

commit a89cde689643a747000006b32d8bd71be0a43c1e
Author: Jiang Tian <jt...@163.com>
AuthorDate: Tue Oct 29 14:42:44 2019 +0800

    [IOTDB-205]Support storage-group-level data ttl (#429)
    
    * add set/unset TTL for Storage group
---
 .../4-Operation Manual/7-IoTDB Query Language.md   |  39 +++
 .../4-Operation Manual/7-IoTDB Query Statement.md  |  48 ++-
 .../main/java/org/apache/iotdb/jdbc/Constant.java  |  25 +-
 .../org/apache/iotdb/jdbc/IoTDBConnection.java     |  46 ++-
 .../apache/iotdb/jdbc/IoTDBDatabaseMetadata.java   | 265 +++--------------
 .../apache/iotdb/jdbc/IoTDBMetadataResultSet.java  |  35 +--
 .../org/apache/iotdb/jdbc/IoTDBQueryResultSet.java |   2 +-
 .../org/apache/iotdb/jdbc/IoTDBSQLException.java   |   5 +
 .../java/org/apache/iotdb/jdbc/IoTDBStatement.java |  55 ++--
 .../iotdb/jdbc/IoTDBDatabaseMetadataTest.java      |  54 ++--
 .../org/apache/iotdb/jdbc/IoTDBStatementTest.java  |  40 +--
 .../resources/conf/iotdb-engine.properties         |   7 +
 .../org/apache/iotdb/db/sql/parse/TqlLexer.g       |   8 +
 .../org/apache/iotdb/db/sql/parse/TqlParser.g      |  42 +++
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |  17 +-
 .../org/apache/iotdb/db/conf/IoTDBConstant.java    |   9 +-
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |   3 +
 .../db/conf/directories/DirectoryManager.java      |  12 +-
 .../directories/strategy/DirectoryStrategy.java    |  21 +-
 .../org/apache/iotdb/db/engine/StorageEngine.java  |  81 +++--
 .../iotdb/db/engine/cache/DeviceMetaDataCache.java |   3 -
 .../iotdb/db/engine/cache/TsFileMetaDataCache.java |   3 -
 .../iotdb/db/engine/memtable/AbstractMemTable.java |   8 +-
 .../apache/iotdb/db/engine/memtable/IMemTable.java |   2 +-
 .../db/engine/merge/manage/MergeResource.java      |  48 +--
 .../iotdb/db/engine/merge/task/MergeTask.java      |   4 +
 .../db/engine/querycontext/QueryDataSource.java    |  32 ++
 .../engine/storagegroup/StorageGroupProcessor.java | 325 +++++++++++++++------
 .../db/engine/storagegroup/TsFileProcessor.java    |   7 +-
 .../db/engine/storagegroup/TsFileResource.java     |  54 +++-
 .../db/exception/NotStorageGroupException.java     |  20 +-
 .../iotdb/db/exception/OutOfTTLException.java      |  22 +-
 .../java/org/apache/iotdb/db/metadata/MGraph.java  |  37 +--
 .../org/apache/iotdb/db/metadata/MManager.java     | 121 ++++----
 .../java/org/apache/iotdb/db/metadata/MNode.java   |  30 ++
 .../java/org/apache/iotdb/db/metadata/MTree.java   | 247 ++++++----------
 .../iotdb/db/metadata/MetadataOperationType.java   |   3 +-
 .../java/org/apache/iotdb/db/metadata/PTree.java   |  66 ++---
 .../org/apache/iotdb/db/monitor/StatMonitor.java   |   3 +-
 .../org/apache/iotdb/db/qp/QueryProcessor.java     |   1 +
 .../apache/iotdb/db/qp/constant/SQLConstant.java   |   9 +
 .../qp/executor/AbstractQueryProcessExecutor.java  |  51 +++-
 .../iotdb/db/qp/executor/QueryProcessExecutor.java |  46 ++-
 .../org/apache/iotdb/db/qp/logical/Operator.java   |   3 +-
 .../iotdb/db/qp/logical/sys/SetTTLOperator.java    |  32 +-
 .../iotdb/db/qp/logical/sys/ShowTTLOperator.java   |  24 +-
 .../physical/sys/SetTTLPlan.java}                  |  52 ++--
 .../iotdb/db/qp/physical/sys/ShowTTLPlan.java      |  30 ++
 .../iotdb/db/qp/strategy/LogicalGenerator.java     | 290 ++++++++++++------
 .../iotdb/db/qp/strategy/PhysicalGenerator.java    |  18 ++
 .../iotdb/db/query/context/QueryContext.java       |  14 +
 .../iotdb/db/query/control/FileReaderManager.java  |  44 ++-
 .../iotdb/db/query/control/JobFileManager.java     |  33 ++-
 .../dataset/{AuthDataSet.java => ListDataSet.java} |   4 +-
 .../groupby/GroupByWithoutValueFilterDataSet.java  |   1 +
 .../db/query/executor/AggregateEngineExecutor.java |   4 +
 .../fileRelated/UnSealedTsFileIterateReader.java   |   2 +-
 .../UnSealedTsFileReaderByTimestamp.java           |   2 +-
 .../resourceRelated/UnseqResourceMergeReader.java  |   2 +-
 .../UnseqResourceReaderByTimestamp.java            |   2 +-
 .../SeriesReaderWithoutValueFilter.java            |   9 +-
 .../iotdb/db/service/JDBCServiceEventHandler.java  |  13 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java | 111 +++----
 .../java/org/apache/iotdb/db/utils/TestOnly.java   |  23 +-
 .../db/engine/memtable/PrimitiveMemTableTest.java  |   4 +-
 .../engine/modification/DeletionFileNodeTest.java  |  12 +-
 .../db/engine/modification/DeletionQueryTest.java  |  17 +-
 .../storagegroup/FileNodeManagerBenchmark.java     |  16 +-
 .../storagegroup/StorageGroupProcessorTest.java    |   6 +-
 .../iotdb/db/engine/storagegroup/TTLTest.java      | 305 +++++++++++++++++++
 .../engine/storagegroup/TsFileProcessorTest.java   |   3 +-
 .../iotdb/db/integration/IoTDBTimeZoneIT.java      |  10 +-
 .../apache/iotdb/db/integration/IoTDBTtlIT.java    | 205 +++++++++++++
 .../iotdb/db/integration/IoTDBVersionIT.java       |  13 +-
 .../iotdb/db/metadata/MManagerAdvancedTest.java    |  22 +-
 .../iotdb/db/metadata/MManagerBasicTest.java       |  36 +--
 .../iotdb/db/metadata/MManagerImproveTest.java     |  51 ++--
 .../org/apache/iotdb/db/metadata/MTreeTest.java    | 151 ++++++----
 .../db/query/control/FileReaderManagerTest.java    |   6 +-
 .../iotdb/db/query/reader/ReaderTestHelper.java    |   2 +-
 .../fileRelated/UnSealedTsFileReaderTest.java      |  10 +-
 .../resourceRelated/UnseqResourceReaderTest.java   |   3 +-
 .../apache/iotdb/db/utils/EnvironmentUtils.java    |   5 +
 .../iotdb/db/writelog/recover/LogReplayerTest.java |   2 +-
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |   4 +-
 85 files changed, 2274 insertions(+), 1278 deletions(-)

diff --git a/docs/Documentation-CHN/UserGuide/4-Operation Manual/7-IoTDB Query Language.md b/docs/Documentation-CHN/UserGuide/4-Operation Manual/7-IoTDB Query Language.md
index 2f2c2f2..75e27ac 100644
--- a/docs/Documentation-CHN/UserGuide/4-Operation Manual/7-IoTDB Query Language.md	
+++ b/docs/Documentation-CHN/UserGuide/4-Operation Manual/7-IoTDB Query Language.md	
@@ -509,6 +509,44 @@ SELECT SUM(Path) (COMMA SUM(Path))* FROM <FromClause> [WHERE <WhereClause>]?
 Eg. SELECT SUM(temperature) FROM root.ln.wf01.wt01 WHERE root.ln.wf01.wt01.temperature < 24
 Note: the statement needs to satisfy this constraint: <PrefixPath> + <Path> = <Timeseries>
 ```
+
+### TTL
+IoTDB支持对存储组级别设置数据存活时间(TTL),这使得IoTDB可以定期、自动地删除一定时间之前的数据。合理使用TTL
+可以帮助您控制IoTDB占用的总磁盘空间以避免出现磁盘写满等异常。并且,随着文件数量的增多,查询性能往往随之下降,
+内存占用也会有所提高。及时地删除一些较老的文件有助于使查询性能维持在一个较高的水平和减少内存资源的占用。
+IoTDB中的TTL操作通可以由以下的语句进行实现:
+
+* 设置 TTL
+```
+SET TTL TO StorageGroupName TTLTime
+Eg. SET TTL TO root.group1 3600000
+这个例子展示了如何使得root.group1这个存储组只保留近一个小时的数据,一个小时前的数据会被删除或者进入不可见状态。
+注意: TTLTime 应是毫秒时间戳。一旦TTL被设置,超过TTL时间范围的写入将被拒绝。
+```
+
+* 取消 TTL
+```
+UNSET TTL TO StorageGroupName
+Eg. UNSET TTL TO root.group1
+这个例子展示了如何取消存储组root.group1的TTL,这将使得该存储组接受任意时刻的数据。
+```
+
+* 显示 TTL
+```
+SHOW ALL TTL
+SHOW TTL ON StorageGroupNames
+Eg.1 SHOW ALL TTL
+这个例子会给出所有存储组的TTL。
+Eg.2 SHOW TTL ON root.group1,root.group2,root.group3
+这个例子会显示指定的三个存储组的TTL。
+注意: 没有设置TTL的存储组的TTL将显示为null。
+```
+
+注意:当您对某个存储组设置TTL的时候,超过TTL范围的数据将会立即不可见。但由于数据文件可能混合包含处在TTL范围内
+与范围外的数据,同时数据文件可能正在接受查询,数据文件的物理删除不会立即进行。如果你在此时取消或者调大TTL,
+一部分之前不可见的数据可能重新可见,而那些已经被物理删除的数据则将永久丢失。也就是说,TTL操作不会原子性地删除
+对应的数据。因此我们不推荐您频繁修改TTL,除非您能接受该操作带来的一定程度的不可预知性。
+
 ## 参考
 
 ### 关键字
@@ -623,3 +661,4 @@ eg. root.ln.wf01.wt01.*
 eg. *.wt01.*
 eg. *
 ```
+
diff --git a/docs/Documentation/UserGuide/4-Operation Manual/7-IoTDB Query Statement.md b/docs/Documentation/UserGuide/4-Operation Manual/7-IoTDB Query Statement.md
index a0dfb59..3b4f91b 100644
--- a/docs/Documentation/UserGuide/4-Operation Manual/7-IoTDB Query Statement.md	
+++ b/docs/Documentation/UserGuide/4-Operation Manual/7-IoTDB Query Statement.md	
@@ -612,6 +612,52 @@ Eg. SELECT SUM(temperature) FROM root.ln.wf01.wt01 WHERE root.ln.wf01.wt01.tempe
 Note: the statement needs to satisfy this constraint: <PrefixPath> + <Path> = <Timeseries>
 ```
 
+### TTL
+IoTDB supports storage-level TTL settings, which means it is able to delete old data
+automatically and periodically. The benefit of using TTL is that hopefully you can control the 
+total disk space usage and prevent the machine from running out of disks. Moreover, the query
+performance may downgrade as the total number of files goes up and the memory usage also increase
+as there are more files. Timely removing such files helps to keep at a high query performance
+level and reduce memory usage. The TTL operations in IoTDB are supported by the following three
+statements:
+
+* Set TTL
+```
+SET TTL TO StorageGroupName TTLTime
+Eg. SET TTL TO root.group1 3600000
+This example means that for data in root.group1, only that of the latest 1 hour will remain, the
+older one is removed or made invisible. 
+Note: TTLTime should be millisecond timestamp. When TTL is set, insertions that fall
+out of TTL will be rejected.
+```
+
+* Unset TTL
+```
+UNSET TTL TO StorageGroupName
+Eg. UNSET TTL TO root.group1
+This example means that data of all time will be accepted in this group. 
+```
+
+* Show TTL
+```
+SHOW ALL TTL
+SHOW TTL ON StorageGroupNames
+Eg.1 SHOW ALL TTL
+This example will show TTLs of all storage groups.
+Eg.2 SHOW TTL ON root.group1,root.group2,root.group3
+This example will show TTLs of the specified 3 groups.
+Notice: storage groups without TTL will show a "null"
+```
+
+Notice: When you set TTL to some storage groups, data out of the TTL will be made invisible
+immediately, but because the data files may contain both out-dated and living data or the data files may
+be being used by queries, the physical removal of data is stale. If you increase or unset TTL
+just after setting it previously, some previously invisible data may be seen again, but the
+physically removed one is lost forever. In other words, different from delete statement, the
+atomicity of data deletion is not guaranteed for efficiency concerns. So we recommend that you do
+not change the TTL once it is set or at least do not reset it frequently, unless you are determined 
+to suffer the unpredictability. 
+
 ## Reference
 
 ### Keywords
@@ -725,4 +771,4 @@ eg. root.*.wf01.wt01.status
 eg. root.ln.wf01.wt01.*
 eg. *.wt01.*
 eg. *
-```
\ No newline at end of file
+```
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
index 3014199..15cd761 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
@@ -24,32 +24,33 @@ public class Constant {
 
   public static final String GLOBAL_DB_NAME = "IoTDB";
 
-  public static final String GLOBAL_DB_VERSION = "0.8.0-SNAPSHOT";
+  static final String GLOBAL_DB_VERSION = "0.8.0-SNAPSHOT";
 
   public static final String GLOBAL_COLUMN_REQ = "COLUMN";
 
-  public static final String GLOBAL_SHOW_DEVICES_REQ = "SHOW_DEVICES";
+  static final String GLOBAL_SHOW_DEVICES_REQ = "SHOW_DEVICES";
 
-  public static final String GLOBAL_SHOW_TIMESERIES_REQ = "SHOW_TIMESERIES";
+  static final String GLOBAL_SHOW_TIMESERIES_REQ = "SHOW_TIMESERIES";
 
-  public static final String GLOBAL_COUNT_TIMESERIES_REQ = "COUNT_TIMESERIES";
+  static final String GLOBAL_COUNT_TIMESERIES_REQ = "COUNT_TIMESERIES";
 
-  public static final String GLOBAL_COUNT_NODE_TIMESERIES_REQ = "COUNT_NODE_TIMESERIES";
+  static final String GLOBAL_COUNT_NODE_TIMESERIES_REQ = "COUNT_NODE_TIMESERIES";
 
-  public static final String GLOBAL_COUNT_NODES_REQ = "COUNT_NODES";
+  static final String GLOBAL_COUNT_NODES_REQ = "COUNT_NODES";
 
-  public static final String GLOBAL_SHOW_STORAGE_GROUP_REQ = "SHOW_STORAGE_GROUP";
+  static final String GLOBAL_SHOW_STORAGE_GROUP_REQ = "SHOW_STORAGE_GROUP";
 
-  public static final String GLOBAL_COLUMNS_REQ = "ALL_COLUMNS";
+  static final String GLOBAL_COLUMNS_REQ = "ALL_COLUMNS";
 
   // catalog parameters used for DatabaseMetaData.getColumns()
   public static final String CATALOG_COLUMN = "col";
   public static final String CATALOG_TIMESERIES = "ts";
   public static final String CATALOG_STORAGE_GROUP = "sg";
   public static final String CATALOG_DEVICES = "devices";
-  public static final String COUNT_TIMESERIES = "cntts";
-  public static final String COUNT_NODE_TIMESERIES = "cntnodets";
-  public static final String COUNT_NODES = "cntnode";
 
-  public static final String METHOD_NOT_SUPPORTED = "Method not supported";
+  static final String COUNT_TIMESERIES = "cntts";
+  static final String COUNT_NODE_TIMESERIES = "cntnodets";
+  static final String COUNT_NODES = "cntnode";
+
+  static final String METHOD_NOT_SUPPORTED = "Method not supported";
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
index 368b118..901c4b9 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
@@ -54,7 +54,7 @@ public class IoTDBConnection implements Connection {
   private static final Logger logger = LoggerFactory.getLogger(IoTDBConnection.class);
   private final TSProtocolVersion protocolVersion = TSProtocolVersion.IOTDB_SERVICE_PROTOCOL_V1;
   public TSIService.Iface client = null;
-  public TS_SessionHandle sessionHandle = null;
+  TS_SessionHandle sessionHandle = null;
   private IoTDBConnectionParams params;
   private boolean isClosed = true;
   private SQLWarning warningChain = null;
@@ -103,7 +103,7 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public void clearWarnings() throws SQLException {
+  public void clearWarnings() {
     warningChain = null;
   }
 
@@ -172,7 +172,7 @@ public class IoTDBConnection implements Connection {
               resultSetConcurrency));
     }
     if (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE) {
-      throw new SQLException(String.format("Statements with resultset type %d are not supported",
+      throw new SQLException(String.format("Statements with ResultSet type %d are not supported",
           resultSetType));
     }
     return new IoTDBStatement(this, client, sessionHandle, zoneId);
@@ -189,18 +189,18 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public boolean getAutoCommit() throws SQLException {
+  public boolean getAutoCommit() {
     return autoCommit;
   }
 
   @Override
-  public void setAutoCommit(boolean arg0) throws SQLException {
+  public void setAutoCommit(boolean arg0) {
     autoCommit = arg0;
   }
 
   @Override
-  public String getCatalog() throws SQLException {
-    return "no cata log";
+  public String getCatalog() {
+    return "no catalog";
   }
 
   @Override
@@ -224,7 +224,7 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getHoldability() throws SQLException {
+  public int getHoldability() {
     // throw new SQLException("Method not supported");
     return 0;
   }
@@ -243,7 +243,7 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getNetworkTimeout() throws SQLException {
+  public int getNetworkTimeout() {
     return Config.connectionTimeoutInMs;
   }
 
@@ -258,7 +258,7 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public int getTransactionIsolation() throws SQLException {
+  public int getTransactionIsolation() {
     return Connection.TRANSACTION_NONE;
   }
 
@@ -278,17 +278,17 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public SQLWarning getWarnings() throws SQLException {
+  public SQLWarning getWarnings() {
     return warningChain;
   }
 
   @Override
-  public boolean isClosed() throws SQLException {
+  public boolean isClosed() {
     return isClosed;
   }
 
   @Override
-  public boolean isReadOnly() throws SQLException {
+  public boolean isReadOnly() {
     return false;
   }
 
@@ -364,12 +364,12 @@ public class IoTDBConnection implements Connection {
   }
 
   @Override
-  public void rollback() throws SQLException {
+  public void rollback() {
     // do nothing in rollback
   }
 
   @Override
-  public void rollback(Savepoint arg0) throws SQLException {
+  public void rollback(Savepoint arg0) {
     // do nothing in rollback
   }
 
@@ -415,11 +415,11 @@ public class IoTDBConnection implements Connection {
       } catch (IoTDBRPCException e) {
         // failed to connect, disconnect from the server
         transport.close();
-        throw new IoTDBSQLException(e.getMessage());
+        throw new IoTDBSQLException(e.getMessage(), openResp.getStatus());
       }
       if (protocolVersion.getValue() != openResp.getServerProtocolVersion().getValue()) {
         throw new TException(String
-            .format("Protocol not supported, Client version is {}, but Server version is {}",
+            .format("Protocol not supported, Client version is %d, but Server version is %d",
                 protocolVersion.getValue(), openResp.getServerProtocolVersion().getValue()));
       }
       setProtocol(openResp.getServerProtocolVersion());
@@ -438,7 +438,7 @@ public class IoTDBConnection implements Connection {
     isClosed = false;
   }
 
-  public boolean reconnect() {
+  boolean reconnect() {
     boolean flag = false;
     for (int i = 1; i <= Config.RETRY_NUM; i++) {
       try {
@@ -476,7 +476,7 @@ public class IoTDBConnection implements Connection {
     try {
       RpcUtils.verifySuccess(resp.getStatus());
     } catch (IoTDBRPCException e) {
-      throw new IoTDBSQLException(e.getMessage());
+      throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
     }
     return resp.getTimeZone();
   }
@@ -487,7 +487,7 @@ public class IoTDBConnection implements Connection {
     try {
       RpcUtils.verifySuccess(resp);
     } catch (IoTDBRPCException e) {
-      throw new IoTDBSQLException(e.getMessage());
+      throw new IoTDBSQLException(e.getMessage(), resp);
     }
     this.zoneId = ZoneId.of(zoneId);
   }
@@ -496,11 +496,7 @@ public class IoTDBConnection implements Connection {
     return client.getProperties();
   }
 
-  public TSProtocolVersion getProtocol() {
-    return protocol;
-  }
-
-  public void setProtocol(TSProtocolVersion protocol) {
+  private void setProtocol(TSProtocolVersion protocol) {
     this.protocol = protocol;
   }
 
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
index 8dfabf1..c88aac9 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
@@ -39,7 +39,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           .getLogger(IoTDBDatabaseMetadata.class);
   private static final String METHOD_NOT_SUPPORTED_STRING = "Method not supported";
 
-  public IoTDBDatabaseMetadata(IoTDBConnection connection, TSIService.Iface client) {
+  IoTDBDatabaseMetadata(IoTDBConnection connection, TSIService.Iface client) {
     this.connection = connection;
     this.client = client;
   }
@@ -84,11 +84,11 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           return new IoTDBMetadataResultSet(resp.getColumnsList(), MetadataType.COLUMN);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching column metadata", e);
+          throw new TException("Connection error when fetching column metadata", e);
         }
       case Constant.CATALOG_DEVICES:
         req = new TSFetchMetadataReq(Constant.GLOBAL_SHOW_DEVICES_REQ);
@@ -98,11 +98,11 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           return new IoTDBMetadataResultSet(resp.getDevices(), MetadataType.DEVICES);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching device metadata", e);
+          throw new TException("Connection error when fetching device metadata", e);
         }
       case Constant.CATALOG_STORAGE_GROUP:
         req = new TSFetchMetadataReq(Constant.GLOBAL_SHOW_STORAGE_GROUP_REQ);
@@ -111,12 +111,12 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           Set<String> showStorageGroup = resp.getStorageGroups();
           return new IoTDBMetadataResultSet(showStorageGroup, MetadataType.STORAGE_GROUP);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching storage group metadata", e);
+          throw new TException("Connection error when fetching storage group metadata", e);
         }
       case Constant.CATALOG_TIMESERIES:
         req = new TSFetchMetadataReq(Constant.GLOBAL_SHOW_TIMESERIES_REQ);
@@ -126,12 +126,12 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           List<List<String>> showTimeseriesList = resp.getTimeseriesList();
           return new IoTDBMetadataResultSet(showTimeseriesList, MetadataType.TIMESERIES);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching timeseries metadata", e);
+          throw new TException("Connection error when fetching timeseries metadata", e);
         }
       case Constant.COUNT_TIMESERIES:
         req = new TSFetchMetadataReq(Constant.GLOBAL_COUNT_TIMESERIES_REQ);
@@ -141,7 +141,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           return new IoTDBMetadataResultSet(resp.getTimeseriesNum(), MetadataType.COUNT_TIMESERIES);
         } catch (TException e) {
@@ -153,7 +153,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
     }
   }
 
-  public ResultSet getNodes(String catalog, String schemaPattern, String columnPattern,
+  ResultSet getNodes(String catalog, String schemaPattern, String columnPattern,
       String devicePattern, int nodeLevel) throws SQLException {
     try {
       return getNodesFunc(catalog, schemaPattern, nodeLevel);
@@ -191,11 +191,11 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           return new IoTDBMetadataResultSet(resp.getNodesList().size(), IoTDBMetadataResultSet.MetadataType.COUNT_NODES);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching node metadata", e);
+          throw new TException("Connection error when fetching node metadata", e);
         }
       case Constant.COUNT_NODE_TIMESERIES:
         req = new TSFetchMetadataReq(Constant.GLOBAL_COUNT_NODE_TIMESERIES_REQ);
@@ -206,11 +206,11 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           try {
             RpcUtils.verifySuccess(resp.getStatus());
           } catch (IoTDBRPCException e) {
-            throw new IoTDBSQLException(e.getMessage());
+            throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
           return new IoTDBMetadataResultSet(resp.getNodeTimeseriesNum(), IoTDBMetadataResultSet.MetadataType.COUNT_NODE_TIMESERIES);
         } catch (TException e) {
-          throw new TException("Conncetion error when fetching node metadata", e);
+          throw new TException("Connection error when fetching node metadata", e);
         }
       default:
         throw new SQLException(catalog + " is not supported. Please refer to the user guide"
@@ -220,68 +220,57 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public <T> T unwrap(Class<T> iface) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean allProceduresAreCallable() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean allTablesAreSelectable() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean deletesAreDetected(int arg0) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean generatedKeyAlwaysReturned() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getAttributes(String arg0, String arg1, String arg2, String arg3)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
@@ -289,43 +278,37 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public ResultSet getBestRowIdentifier(String arg0, String arg1, String arg2, int arg3,
       boolean arg4)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getCatalogSeparator() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getCatalogTerm() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getCatalogs() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getClientInfoProperties() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getColumnPrivileges(String arg0, String arg1, String arg2,
       String arg3) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public Connection getConnection() throws SQLException {
+  public Connection getConnection() {
     return connection;
   }
 
@@ -333,360 +316,303 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public ResultSet getCrossReference(String arg0, String arg1, String arg2, String arg3,
       String arg4, String arg5)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public int getDatabaseMajorVersion() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getDatabaseMajorVersion() {
     return 0;
   }
 
   @Override
-  public int getDatabaseMinorVersion() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getDatabaseMinorVersion() {
     return 0;
   }
 
   @Override
-  public String getDatabaseProductName() throws SQLException {
+  public String getDatabaseProductName() {
     return Constant.GLOBAL_DB_NAME;
   }
 
   @Override
-  public String getDatabaseProductVersion() throws SQLException {
+  public String getDatabaseProductVersion() {
     return Constant.GLOBAL_DB_VERSION;
   }
 
   @Override
-  public int getDefaultTransactionIsolation() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getDefaultTransactionIsolation() {
     return 0;
   }
 
   @Override
   public int getDriverMajorVersion() {
-    // TODO Auto-generated method stub
     return 0;
   }
 
   @Override
   public int getDriverMinorVersion() {
-    // TODO Auto-generated method stub
     return 0;
   }
 
   @Override
   public String getDriverName() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getDriverVersion() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getExportedKeys(String arg0, String arg1, String arg2) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getExtraNameCharacters() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getFunctionColumns(String arg0, String arg1, String arg2, String arg3)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getFunctions(String arg0, String arg1, String arg2) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getIdentifierQuoteString() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getImportedKeys(String arg0, String arg1, String arg2) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getIndexInfo(String arg0, String arg1, String arg2, boolean arg3, boolean arg4)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public int getJDBCMajorVersion() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getJDBCMajorVersion() {
     return 0;
   }
 
   @Override
-  public int getJDBCMinorVersion() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getJDBCMinorVersion() {
     return 0;
   }
 
   @Override
-  public int getMaxBinaryLiteralLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxBinaryLiteralLength() {
     return 0;
   }
 
   @Override
-  public int getMaxCatalogNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxCatalogNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxCharLiteralLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxCharLiteralLength() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnsInGroupBy() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnsInGroupBy() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnsInIndex() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnsInIndex() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnsInOrderBy() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnsInOrderBy() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnsInSelect() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnsInSelect() {
     return 0;
   }
 
   @Override
-  public int getMaxColumnsInTable() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxColumnsInTable() {
     return 0;
   }
 
   @Override
-  public int getMaxConnections() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxConnections() {
     return 0;
   }
 
   @Override
-  public int getMaxCursorNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxCursorNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxIndexLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxIndexLength() {
     return 0;
   }
 
   @Override
-  public int getMaxProcedureNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxProcedureNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxRowSize() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxRowSize() {
     return 0;
   }
 
   @Override
-  public int getMaxSchemaNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxSchemaNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxStatementLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxStatementLength() {
     return 0;
   }
 
   @Override
-  public int getMaxStatements() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxStatements() {
     return 0;
   }
 
   @Override
-  public int getMaxTableNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxTableNameLength() {
     return 0;
   }
 
   @Override
-  public int getMaxTablesInSelect() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxTablesInSelect() {
     return 0;
   }
 
   @Override
-  public int getMaxUserNameLength() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getMaxUserNameLength() {
     return 0;
   }
 
   @Override
   public String getNumericFunctions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getPrimaryKeys(String arg0, String arg1, String arg2) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getProcedureColumns(String arg0, String arg1, String arg2, String arg3)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getProcedureTerm() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getProcedures(String arg0, String arg1, String arg2) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern,
       String columnNamePattern) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public int getResultSetHoldability() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getResultSetHoldability() {
     return 0;
   }
 
   @Override
   public RowIdLifetime getRowIdLifetime() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getSQLKeywords() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public int getSQLStateType() throws SQLException {
-    // TODO Auto-generated method stub
+  public int getSQLStateType() {
     return 0;
   }
 
   @Override
   public String getSchemaTerm() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getSchemas() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getSearchStringEscape() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getStringFunctions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getSystemFunctions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getTableTypes() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
@@ -694,19 +620,16 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern,
       String[] types)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public String getTimeDateFunctions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getTypeInfo() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
@@ -714,572 +637,478 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern,
       int[] types)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
-  public String getURL() throws SQLException {
+  public String getURL() {
     // TODO: Return the URL for this DBMS or null if it cannot be generated
     return null;
   }
 
   @Override
   public String getUserName() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public ResultSet getVersionColumns(String catalog, String schema, String table)
       throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean insertsAreDetected(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean isCatalogAtStart() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean isReadOnly() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean locatorsUpdateCopy() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean nullPlusNonNullIsNull() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean nullsAreSortedAtEnd() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean nullsAreSortedAtStart() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean nullsAreSortedHigh() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean nullsAreSortedLow() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean othersDeletesAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean othersInsertsAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean othersUpdatesAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean ownDeletesAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean ownInsertsAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean ownUpdatesAreVisible(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesLowerCaseIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesMixedCaseIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesUpperCaseIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsANSI92EntryLevelSQL() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsANSI92FullSQL() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsANSI92IntermediateSQL() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsAlterTableWithAddColumn() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsAlterTableWithDropColumn() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsBatchUpdates() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCatalogsInDataManipulation() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCatalogsInProcedureCalls() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCatalogsInTableDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsColumnAliasing() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsConvert() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsConvert(int fromType, int toType) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCoreSQLGrammar() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsCorrelatedSubqueries() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsDifferentTableCorrelationNames() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsExpressionsInOrderBy() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsExtendedSQLGrammar() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsFullOuterJoins() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsGetGeneratedKeys() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsGroupBy() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsGroupByBeyondSelect() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsGroupByUnrelated() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsIntegrityEnhancementFacility() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsLikeEscapeClause() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsLimitedOuterJoins() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMinimumSQLGrammar() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMixedCaseIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMultipleOpenResults() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMultipleResultSets() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsMultipleTransactions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsNamedParameters() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsNonNullableColumns() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOrderByUnrelated() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsOuterJoins() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsPositionedDelete() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsPositionedUpdate() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsResultSetHoldability(int holdability) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsResultSetType(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSavepoints() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSchemasInDataManipulation() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSchemasInIndexDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSchemasInProcedureCalls() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSchemasInTableDefinitions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSelectForUpdate() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsStatementPooling() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsStoredProcedures() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSubqueriesInComparisons() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSubqueriesInExists() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSubqueriesInIns() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsSubqueriesInQuantifieds() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsTableCorrelationNames() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsTransactions() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsUnion() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean supportsUnionAll() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean updatesAreDetected(int type) throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean usesLocalFilePerTable() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
   @Override
   public boolean usesLocalFiles() throws SQLException {
-    // TODO Auto-generated method stub
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
   }
 
@@ -1344,7 +1173,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
     try {
       RpcUtils.verifySuccess(resp.getStatus());
     } catch (IoTDBRPCException e) {
-      throw new IoTDBSQLException(e.getMessage());
+      throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
     }
     return resp.getMetadataInJson();
   }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
index 532fbd8..c1e319a 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
@@ -25,17 +25,18 @@ import java.util.*;
 
 public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
 
-  public static final String GET_STRING_COLUMN = "COLUMN";
-  public static final String GET_STRING_STORAGE_GROUP = "STORAGE_GROUP";
-  public static final String GET_STRING_TIMESERIES_NUM = "TIMESERIES_NUM";
-  public static final String GET_STRING_NODES_NUM = "NODE_NUM";
-  public static final String GET_STRING_NODE_PATH = "NODE_PATH";
-  public static final String GET_STRING_NODE_TIMESERIES_NUM = "NODE_TIMESERIES_NUM";
-  public static final String GET_STRING_TIMESERIES_NAME = "Timeseries";
-  public static final String GET_STRING_DEVICES = "DEVICES";
-  public static final String GET_STRING_TIMESERIES_STORAGE_GROUP = "Storage Group";
+  private static final String GET_STRING_COLUMN = "COLUMN";
+  private static final String GET_STRING_STORAGE_GROUP = "STORAGE_GROUP";
+  private static final String GET_STRING_TIMESERIES_NUM = "TIMESERIES_NUM";
+  private static final String GET_STRING_NODES_NUM = "NODE_NUM";
+  private static final String GET_STRING_NODE_PATH = "NODE_PATH";
+  private static final String GET_STRING_NODE_TIMESERIES_NUM = "NODE_TIMESERIES_NUM";
+  private static final String GET_STRING_TIMESERIES_NAME = "Timeseries";
+  private static final String GET_STRING_DEVICES = "DEVICES";
+  private static final String GET_STRING_TIMESERIES_STORAGE_GROUP = "Storage Group";
+
   public static final String GET_STRING_TIMESERIES_DATATYPE = "DataType";
-  public static final String GET_STRING_TIMESERIES_ENCODING = "Encoding";
+  private static final String GET_STRING_TIMESERIES_ENCODING = "Encoding";
   private Iterator<?> columnItr;
   private MetadataType type;
   private String currentColumn;
@@ -58,7 +59,7 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
   /**
    * Constructor used for the result of DatabaseMetadata.getColumns()
    */
-  public IoTDBMetadataResultSet(Object object, MetadataType type) throws SQLException {
+  IoTDBMetadataResultSet(Object object, MetadataType type) throws SQLException {
     this.type = type;
     switch (type) {
       case COLUMN:
@@ -87,7 +88,7 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
         columnItr = showTimeseriesList.iterator();
         break;
       case COUNT_TIMESERIES:
-        String tsNum = (String) object.toString();
+        String tsNum = object.toString();
         timeseriesNumList = new ArrayList<>();
         timeseriesNumList.add(tsNum);
         colCount = 1;
@@ -95,7 +96,7 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
         columnItr = timeseriesNumList.iterator();
         break;
       case COUNT_NODES:
-        String ndNum = (String) object.toString();
+        String ndNum = object.toString();
         nodesNumList = new ArrayList<>();
         nodesNumList.add(ndNum);
         colCount = 1;
@@ -229,12 +230,12 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
   }
 
   @Override
-  public ResultSetMetaData getMetaData() throws SQLException {
+  public ResultSetMetaData getMetaData() {
     return new IoTDBMetadataResultMetadata(showLabels);
   }
 
   @Override
-  public boolean next() throws SQLException {
+  public boolean next() {
     boolean hasNext = columnItr.hasNext();
     if (hasNext) {
       switch (type) {
@@ -333,7 +334,7 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
   }
 
   @Override
-  public String getString(String columnName) throws SQLException {
+  public String getString(String columnName) {
     // use special key word to judge return content
     switch (columnName) {
       case GET_STRING_STORAGE_GROUP:
@@ -375,7 +376,7 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
   }
 
   @Override
-  public int getType() throws SQLException {
+  public int getType() {
     return type.ordinal();
   }
 
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBQueryResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBQueryResultSet.java
index 3d4d5d3..e7a7d84 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBQueryResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBQueryResultSet.java
@@ -715,7 +715,7 @@ public class IoTDBQueryResultSet implements ResultSet {
         try {
           RpcUtils.verifySuccess(resp.getStatus());
         } catch (IoTDBRPCException e) {
-          throw new IoTDBSQLException(e.getMessage());
+          throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
         }
         if (!resp.hasResultSet) {
           emptyResultSet = true;
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
index dd27fc5..f924078 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.jdbc;
 
 import java.sql.SQLException;
+import org.apache.iotdb.service.rpc.thrift.TSStatus;
 
 public class IoTDBSQLException extends SQLException {
 
@@ -29,6 +30,10 @@ public class IoTDBSQLException extends SQLException {
     super(reason);
   }
 
+  public IoTDBSQLException(String reason, TSStatus status) {
+    super(reason, status.sqlState, status.statusType.code);
+  }
+
   public IoTDBSQLException(Throwable cause) {
     super(cause);
   }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
index 484a232..cd7b3dd 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
@@ -86,12 +86,12 @@ public class IoTDBStatement implements Statement {
    */
   private SQLWarning warningChain = null;
 
-  protected long stmtId = -1;
+  long stmtId = -1;
 
   /**
    * Constructor of IoTDBStatement.
    */
-  public IoTDBStatement(IoTDBConnection connection, TSIService.Iface client,
+  IoTDBStatement(IoTDBConnection connection, TSIService.Iface client,
       TS_SessionHandle sessionHandle,
       int fetchSize, ZoneId zoneId) {
     this.connection = connection;
@@ -102,14 +102,14 @@ public class IoTDBStatement implements Statement {
     this.zoneId = zoneId;
   }
 
-  public IoTDBStatement(IoTDBConnection connection, TSIService.Iface client,
+  IoTDBStatement(IoTDBConnection connection, TSIService.Iface client,
       TS_SessionHandle sessionHandle,
       ZoneId zoneId) {
     this(connection, client, sessionHandle, Config.fetchSize, zoneId);
   }
 
   @Override
-  public boolean isWrapperFor(Class<?> iface) throws SQLException {
+  public boolean isWrapperFor(Class<?> iface) {
     return false;
   }
 
@@ -119,7 +119,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public void addBatch(String sql) throws SQLException {
+  public void addBatch(String sql) {
     if (batchSQLList == null) {
       batchSQLList = new ArrayList<>();
     }
@@ -145,7 +145,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public void clearBatch() throws SQLException {
+  public void clearBatch() {
     if (batchSQLList == null) {
       batchSQLList = new ArrayList<>();
     }
@@ -153,7 +153,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public void clearWarnings() throws SQLException {
+  public void clearWarnings() {
     warningChain = null;
   }
 
@@ -239,11 +239,11 @@ public class IoTDBStatement implements Statement {
         resultSet = databaseMetaData.getColumns(Constant.CATALOG_TIMESERIES, "root", null, null);
         return true;
       } else {
-        String[] cmdSplited = sql.split("\\s+");
-        if (cmdSplited.length != 3) {
+        String[] cmdSplit = sql.split("\\s+");
+        if (cmdSplit.length != 3) {
           throw new SQLException("Error format of \'SHOW TIMESERIES <PATH>\'");
         } else {
-          String path = cmdSplited[2];
+          String path = cmdSplit[2];
           DatabaseMetaData databaseMetaData = connection.getMetaData();
           resultSet = databaseMetaData.getColumns(Constant.CATALOG_TIMESERIES, path, null, null);
           return true;
@@ -258,30 +258,31 @@ public class IoTDBStatement implements Statement {
       resultSet = databaseMetaData.getColumns(Constant.CATALOG_DEVICES, null, null, null);
       return true;
     } else if (sqlToLowerCase.startsWith(COUNT_TIMESERIES_COMMAND_LOWERCASE)) {
-      String[] cmdSplited = sqlToLowerCase.split("\\s+", 4);
-      if (cmdSplited.length != 3 && !(cmdSplited.length == 4 && cmdSplited[3].startsWith("group by level"))) {
+      String[] cmdSplit = sqlToLowerCase.split("\\s+", 4);
+      if (cmdSplit.length != 3 && !(cmdSplit.length == 4 && cmdSplit[3].startsWith("group by level"))) {
         throw new SQLException(
                 "Error format of \'COUNT TIMESERIES <PATH>\' or \'COUNT TIMESERIES <PATH> GROUP BY LEVEL=<INTEGER>\'");
       }
-      if (cmdSplited.length == 3) {
-        String path = cmdSplited[2];
+      if (cmdSplit.length == 3) {
+        String path = cmdSplit[2];
         DatabaseMetaData databaseMetaData = connection.getMetaData();
         resultSet = databaseMetaData.getColumns(Constant.COUNT_TIMESERIES, path, null, null);
         return true;
       } else {
-        String path = cmdSplited[2];
-        int level = Integer.parseInt(cmdSplited[3].replaceAll(" ", "").substring(13));
+
+        String path = cmdSplit[2];
+        int level = Integer.parseInt(cmdSplit[3].replaceAll(" ", "").substring(13));
         IoTDBDatabaseMetadata databaseMetadata = (IoTDBDatabaseMetadata) connection.getMetaData();
         resultSet = databaseMetadata.getNodes(Constant.COUNT_NODE_TIMESERIES, path, null, null, level);
         return true;
       }
     } else if (sqlToLowerCase.startsWith(COUNT_NODES_COMMAND_LOWERCASE)) {
-      String[] cmdSplited = sql.split("\\s+", 4);
-      if (cmdSplited.length != 4 || !(cmdSplited[3].startsWith("level"))) {
+      String[] cmdSplit = sql.split("\\s+", 4);
+      if (cmdSplit.length != 4 && !(cmdSplit[3].startsWith("level"))) {
         throw new SQLException("Error format of \'COUNT NODES <PATH> LEVEL=<INTEGER>\'");
       } else {
-        String path = cmdSplited[2];
-        int level = Integer.parseInt(cmdSplited[3].replaceAll(" ", "").substring(6));
+        String path = cmdSplit[2];
+        int level = Integer.parseInt(cmdSplit[3].replaceAll(" ", "").substring(6));
         IoTDBDatabaseMetadata databaseMetaData = (IoTDBDatabaseMetadata) connection.getMetaData();
         resultSet = databaseMetaData.getNodes(Constant.COUNT_NODES, path, null, null, level);
         return true;
@@ -293,7 +294,7 @@ public class IoTDBStatement implements Statement {
       try {
         RpcUtils.verifySuccess(execResp.getStatus());
       } catch (IoTDBRPCException e) {
-        throw new IoTDBSQLException(e.getMessage());
+        throw new IoTDBSQLException(e.getMessage(), execResp.getStatus());
       }
       if (execResp.getOperationHandle().hasResultSet) {
         this.resultSet = new IoTDBQueryResultSet(this, execResp.getColumns(),
@@ -394,7 +395,7 @@ public class IoTDBStatement implements Statement {
     try {
       RpcUtils.verifySuccess(execResp.getStatus());
     } catch (IoTDBRPCException e) {
-      throw new IoTDBSQLException(e.getMessage());
+      throw new IoTDBSQLException(e.getMessage(), execResp.getStatus());
     }
     this.resultSet = new IoTDBQueryResultSet(this, execResp.getColumns(),
         execResp.getDataTypeList(), execResp.ignoreTimeStamp, client, operationHandle, sql,
@@ -449,13 +450,13 @@ public class IoTDBStatement implements Statement {
     try {
       RpcUtils.verifySuccess(execResp.getStatus());
     } catch (IoTDBRPCException e) {
-      throw new IoTDBSQLException(e.getMessage());
+      throw new IoTDBSQLException(e.getMessage(), execResp.getStatus());
     }
     return 0;
   }
 
   @Override
-  public Connection getConnection() throws SQLException {
+  public Connection getConnection() {
     return connection;
   }
 
@@ -529,7 +530,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public int getQueryTimeout() throws SQLException {
+  public int getQueryTimeout() {
     return this.queryTimeout;
   }
 
@@ -570,7 +571,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public SQLWarning getWarnings() throws SQLException {
+  public SQLWarning getWarnings() {
     return warningChain;
   }
 
@@ -580,7 +581,7 @@ public class IoTDBStatement implements Statement {
   }
 
   @Override
-  public boolean isClosed() throws SQLException {
+  public boolean isClosed() {
     return isClosed;
   }
 
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
index f750a3a..43f79e2 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
@@ -80,7 +80,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void AllColumns() throws Exception {
+  public void AllColumns() {
     List<String> columnList = new ArrayList<>();
     columnList.add("root.vehicle.d0.s0");
     columnList.add("root.vehicle.d0.s1");
@@ -107,7 +107,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -117,7 +117,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void CountTimeseries() throws Exception {
+  public void CountTimeseries() {
     List<String> columnList = new ArrayList<>();
     columnList.add("root.vehicle.d0.s0");
     columnList.add("root.vehicle.d0.s1");
@@ -143,7 +143,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -153,7 +153,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void CountNodes() throws Exception {
+  public void CountNodes() {
     List<String> nodes = new ArrayList<>();
     nodes.add("root.vehicle1.d1");
     nodes.add("root.vehicle1.d2");
@@ -182,7 +182,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -192,7 +192,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void CountNodeTimeseries() throws Exception {
+  public void CountNodeTimeseries() {
     Map<String, String> nodeTimeseriesNum = new LinkedHashMap<>();
     nodeTimeseriesNum.put("root.vehicle.d1", "3");
     nodeTimeseriesNum.put("root.vehicle.d2", "2");
@@ -225,7 +225,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -235,7 +235,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void deviceUnderColumn() throws Exception {
+  public void deviceUnderColumn() {
     List<String> columnList = new ArrayList<>();
     columnList.add("root.vehicle.d0");
 
@@ -260,7 +260,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -270,7 +270,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void device() throws Exception {
+  public void device() {
     Set<String> devicesSet = new HashSet<>();
     devicesSet.add("root.vehicle.d0");
 
@@ -295,7 +295,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -305,9 +305,9 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings({"resource", "serial"})
   @Test
-  public void ShowTimeseriesPath1() throws Exception {
-    List<List<String>> tslist = new ArrayList<>();
-    tslist.add(new ArrayList<String>(4) {
+  public void ShowTimeseriesPath1() {
+    List<List<String>> tsList = new ArrayList<>();
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s0");
         add("root.vehicle");
@@ -315,7 +315,7 @@ public class IoTDBDatabaseMetadataTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s1");
         add("root.vehicle");
@@ -323,7 +323,7 @@ public class IoTDBDatabaseMetadataTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s2");
         add("root.vehicle");
@@ -332,14 +332,14 @@ public class IoTDBDatabaseMetadataTest {
       }
     });
 
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tslist);
+    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
 
     String standard = "Timeseries,Storage Group,DataType,Encoding,\n"
         + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
         + "root.vehicle.d0.s1,root.vehicle,INT64,RLE,\n"
         + "root.vehicle.d0.s2,root.vehicle,FLOAT,RLE,\n";
     try (ResultSet resultSet = databaseMetaData
-        .getColumns(Constant.CATALOG_TIMESERIES, "root", null, null);) {
+        .getColumns(Constant.CATALOG_TIMESERIES, "root", null, null)) {
       ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
       int colCount = resultSetMetaData.getColumnCount();
       StringBuilder resultStr = new StringBuilder();
@@ -355,7 +355,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -365,9 +365,9 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings({"resource", "serial"})
   @Test
-  public void ShowTimeseriesPath2() throws Exception {
-    List<List<String>> tslist = new ArrayList<>();
-    tslist.add(new ArrayList<String>(4) {
+  public void ShowTimeseriesPath2() {
+    List<List<String>> tsList = new ArrayList<>();
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s0");
         add("root.vehicle");
@@ -376,7 +376,7 @@ public class IoTDBDatabaseMetadataTest {
       }
     });
 
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tslist);
+    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
 
     String standard = "DataType,\n" + "INT32,\n";
     try (ResultSet resultSet = databaseMetaData
@@ -392,7 +392,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
@@ -402,7 +402,7 @@ public class IoTDBDatabaseMetadataTest {
    */
   @SuppressWarnings("resource")
   @Test
-  public void ShowStorageGroup() throws Exception {
+  public void ShowStorageGroup() {
     Set<String> sgSet = new HashSet<>();
     sgSet.add("root.vehicle");
     when(fetchMetadataResp.getStorageGroups()).thenReturn(sgSet);
@@ -425,7 +425,7 @@ public class IoTDBDatabaseMetadataTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
 
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
index d91decc..5953fde 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
@@ -31,11 +31,13 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
 import org.apache.iotdb.rpc.TSStatusCode;
-import org.apache.iotdb.service.rpc.thrift.*;
+import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataReq;
+import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
 import org.apache.iotdb.service.rpc.thrift.TSIService.Iface;
-import org.apache.thrift.TException;
+import org.apache.iotdb.service.rpc.thrift.TSStatus;
+import org.apache.iotdb.service.rpc.thrift.TSStatusType;
+import org.apache.iotdb.service.rpc.thrift.TS_SessionHandle;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -76,10 +78,10 @@ public class IoTDBStatementTest {
 
   @SuppressWarnings({"resource", "serial"})
   @Test
-  public void testExecuteSQL1() throws SQLException, TException {
+  public void testExecuteSQL1() throws SQLException {
     IoTDBStatement stmt = new IoTDBStatement(connection, client, sessHandle, zoneID);
-    List<List<String>> tslist = new ArrayList<>();
-    tslist.add(new ArrayList<String>(4) {
+    List<List<String>> tsList = new ArrayList<>();
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s0");
         add("root.vehicle");
@@ -87,7 +89,7 @@ public class IoTDBStatementTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s1");
         add("root.vehicle");
@@ -95,7 +97,7 @@ public class IoTDBStatementTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s2");
         add("root.vehicle");
@@ -107,7 +109,7 @@ public class IoTDBStatementTest {
             + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
             + "root.vehicle.d0.s1,root.vehicle,INT64,RLE,\n"
             + "root.vehicle.d0.s2,root.vehicle,FLOAT,RLE,\n";
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tslist);
+    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
     boolean res = stmt.execute("show timeseries");
     assertTrue(res);
     try (ResultSet resultSet = stmt.getResultSet()) {
@@ -126,17 +128,17 @@ public class IoTDBStatementTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
 
   @SuppressWarnings({"resource", "serial"})
   @Test
-  public void testExecuteSQL2() throws SQLException, TException {
+  public void testExecuteSQL2() throws SQLException {
     IoTDBStatement stmt = new IoTDBStatement(connection, client, sessHandle, zoneID);
-    List<List<String>> tslist = new ArrayList<>();
-    tslist.add(new ArrayList<String>(4) {
+    List<List<String>> tsList = new ArrayList<>();
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s0");
         add("root.vehicle");
@@ -144,7 +146,7 @@ public class IoTDBStatementTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s1");
         add("root.vehicle");
@@ -152,7 +154,7 @@ public class IoTDBStatementTest {
         add("RLE");
       }
     });
-    tslist.add(new ArrayList<String>(4) {
+    tsList.add(new ArrayList<String>(4) {
       {
         add("root.vehicle.d0.s2");
         add("root.vehicle");
@@ -164,7 +166,7 @@ public class IoTDBStatementTest {
         + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
         + "root.vehicle.d0.s1,root.vehicle,INT64,RLE,\n"
         + "root.vehicle.d0.s2,root.vehicle,FLOAT,RLE,\n";
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tslist);
+    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
     boolean res = stmt.execute("show timeseries root.vehicle.d0");
     assertTrue(res);
     try (ResultSet resultSet = stmt.getResultSet()) {
@@ -183,13 +185,13 @@ public class IoTDBStatementTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
     }
   }
 
   @SuppressWarnings({"resource"})
   @Test
-  public void testExecuteSQL3() throws SQLException, TException {
+  public void testExecuteSQL3() throws SQLException {
     IoTDBStatement stmt = new IoTDBStatement(connection, client, sessHandle, zoneID);
     Set<String> sgSet = new HashSet<>();
     sgSet.add("root.vehicle");
@@ -213,7 +215,7 @@ public class IoTDBStatementTest {
       }
       Assert.assertEquals(resultStr.toString(), standard);
     } catch (SQLException e) {
-      System.out.println(e);
+      e.printStackTrace();
       Assert.fail(e.getMessage());
     }
   }
diff --git a/server/src/assembly/resources/conf/iotdb-engine.properties b/server/src/assembly/resources/conf/iotdb-engine.properties
index f5f6419..b4b24bb 100644
--- a/server/src/assembly/resources/conf/iotdb-engine.properties
+++ b/server/src/assembly/resources/conf/iotdb-engine.properties
@@ -171,6 +171,13 @@ concurrent_flush_thread=0
 # (i.e., whether use ChunkBufferPool), value true, false
 chunk_buffer_pool_enable=false
 
+# Default TTL for storage groups that are not set TTL by statements, in ms. If not set (default),
+# the TTL will be unlimited.
+# Notice: if this property is changed, previous created storage group which are not set TTL will
+# also be affected. And negative values are accepted, which means you can only insert future
+# data.
+# default_ttl=36000000
+
 ####################
 ### Merge Configurations
 ####################
diff --git a/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlLexer.g b/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlLexer.g
index c694ed1..c49fb6f 100644
--- a/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlLexer.g
+++ b/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlLexer.g
@@ -265,6 +265,14 @@ K_WATERMARK_EMBEDDING
     : W A T E R M A R K '_' E M B E D D I N G
     ;
 
+K_TTL
+    : T T L
+    ;
+
+K_UNSET
+    : U N S E T
+    ;
+
 //************** logical operator***********
 OPERATOR_AND
     : A N D
diff --git a/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlParser.g b/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlParser.g
index 1d0ae99..fb0aa9d 100644
--- a/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlParser.g
+++ b/server/src/main/antlr3/org/apache/iotdb/db/sql/parse/TqlParser.g
@@ -102,6 +102,9 @@ tokens{
     TOK_PROPERTY_VALUE;
     TOK_GROUPBY_DEVICE;
     TOK_SELECT_INDEX;
+    TOK_TTL;
+    TOK_UNSET;
+    TOK_SHOW;
     TOK_DATE_EXPR;
     TOK_DURATION;
 }
@@ -166,6 +169,8 @@ static {
 	tokenNameMap.put("K_DISABLE", "DISABLE");
 	tokenNameMap.put("K_ALL", "ALL");
 	tokenNameMap.put("K_LIST", "LIST");
+	tokenNameMap.put("K_TTL", "TTL");
+	tokenNameMap.put("K_UNSET", "UNSET");
 	// Operators
 	tokenNameMap.put("DOT", ".");
 	tokenNameMap.put("COLON", ":");
@@ -295,6 +300,7 @@ ddlStatement
     | dropIndex
     | mergeStatement
     | listStatement
+    | ttlStatement
     ;
 
 administrationStatement
@@ -744,4 +750,40 @@ revokeWatermarkEmbedding
 rootOrId
     : K_ROOT
     | ID
+    ;
+
+/*
+****
+*************
+TTL
+*************
+****
+*/
+
+ttlStatement
+    :
+    setTTLStatement
+    | unsetTTLStatement
+    | showTTLStatement
+    ;
+
+setTTLStatement
+    :
+    K_SET K_TTL K_TO path=prefixPath time=INT
+    -> ^(TOK_TTL TOK_SET $path $time)
+    ;
+
+unsetTTLStatement
+    :
+     K_UNSET K_TTL K_TO path=prefixPath
+    -> ^(TOK_TTL TOK_UNSET $path)
+    ;
+
+showTTLStatement
+    :
+    K_SHOW K_TTL K_ON prefixPath (COMMA prefixPath)*
+    -> ^(TOK_TTL TOK_SHOW prefixPath+)
+    |
+    K_SHOW K_ALL K_TTL
+    -> ^(TOK_TTL TOK_SHOW)
     ;
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 7f1e301..4eb5576 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
 public class IoTDBConfig {
 
   private static final Logger logger = LoggerFactory.getLogger(IoTDBConfig.class);
-  public static final String CONFIG_NAME = "iotdb-engine.properties";
+  static final String CONFIG_NAME = "iotdb-engine.properties";
   private static final String MULTI_DIR_STRATEGY_PREFIX =
       "org.apache.iotdb.db.conf.directories.strategy.";
   private static final String DEFAULT_MULTI_DIR_STRATEGY = "MaxDiskUsableSpaceFirstStrategy";
@@ -391,6 +391,13 @@ public class IoTDBConfig {
    */
   private String hdfsPort = "9000";
 
+  /**
+   * default TTL for storage groups that are not set TTL by statements, in ms
+   * Notice: if this property is changed, previous created storage group which are not set TTL will
+   * also be affected.
+   */
+  private long defaultTTL = Long.MAX_VALUE;
+
   public IoTDBConfig() {
     // empty constructor
   }
@@ -1085,4 +1092,12 @@ public class IoTDBConfig {
   public void setHdfsPort(String hdfsPort) {
     this.hdfsPort = hdfsPort;
   }
+
+  public long getDefaultTTL() {
+    return defaultTTL;
+  }
+
+  public void setDefaultTTL(long defaultTTL) {
+    this.defaultTTL = defaultTTL;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConstant.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConstant.java
index c624d22..9fe4780 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConstant.java
@@ -61,9 +61,12 @@ public class IoTDBConstant {
 
   public static final String SHOW_DYNAMIC_PARAMETERS = "show\\s+dynamic\\s+parameters";
 
-  public static final String ROLE = "Role";
-  public static final String USER = "User";
-  public static final String PRIVILEGE = "Privilege";
+  public static final String ROLE = "role";
+  public static final String USER = "user";
+  public static final String PRIVILEGE = "privilege";
+
+  public static final String STORAGE_GROUP = "storage group";
+  public static final String TTL = "ttl";
 
   // data folder name
   public static final String SEQUENCE_FLODER_NAME = "sequence";
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index bc95f45..95297ed 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -294,6 +294,9 @@ public class IoTDBDescriptor {
       conf.setHdfsIp(properties.getProperty("hdfs_ip"));
       conf.setHdfsPort(properties.getProperty("hdfs_port"));
 
+      conf.setDefaultTTL(Long.parseLong(properties.getProperty("default_ttl",
+          String.valueOf(conf.getDefaultTTL()))));
+
       // At the same time, set TSFileConfig
       TSFileDescriptor.getInstance().getConfig().setTSFileStorageFs(properties.getProperty("tsfile_storage_fs"));
       TSFileDescriptor.getInstance().getConfig().setHdfsIp(properties.getProperty("hdfs_ip"));
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java b/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
index 63e4742..8c14adb 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
@@ -87,17 +87,7 @@ public class DirectoryManager {
       }
     }
   }
-
-  // only used by test
-  public String getSequenceFolderForTest() {
-    return sequenceFileFolders.get(0);
-  }
-
-  // only used by test
-  public void setSequenceFolderForTest(String path) {
-    sequenceFileFolders.set(0, path);
-  }
-
+  
   public String getNextFolderForSequenceFile() throws DiskSpaceInsufficientException {
     return getSequenceFileFolder(getNextFolderIndexForSequenceFile());
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java b/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
index 085de13..05f38db 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
@@ -35,7 +35,7 @@ public abstract class DirectoryStrategy {
   /**
    * All the folders of data files, should be init once the subclass is created.
    */
-  protected List<String> folders;
+  List<String> folders;
 
   /**
    * To init folders. Do not recommend to overwrite.
@@ -66,23 +66,4 @@ public abstract class DirectoryStrategy {
    */
   public abstract int nextFolderIndex() throws DiskSpaceInsufficientException;
 
-  /**
-   * Return the actual string value of a folder by its index.
-   *
-   * @param index the index of the folder
-   * @return the string value of the folder
-   */
-  public String getTsFileFolder(int index) {
-    return folders.get(index);
-  }
-
-  // only used by test
-  public String getFolderForTest() {
-    return getTsFileFolder(0);
-  }
-
-  // only used by test
-  public void setFolderForTest(String path) {
-    folders.set(0, path);
-  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
index 8a49841..45e7fd1 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
@@ -21,10 +21,14 @@ package org.apache.iotdb.db.engine;
 import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import org.apache.commons.io.FileUtils;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -32,7 +36,7 @@ import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
 import org.apache.iotdb.db.engine.storagegroup.StorageGroupProcessor;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
-import org.apache.iotdb.db.exception.MetadataErrorException;
+import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.StorageEngineFailureException;
@@ -40,6 +44,7 @@ import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.exception.TsFileProcessorException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 import org.apache.iotdb.db.metadata.MManager;
+import org.apache.iotdb.db.metadata.MNode;
 import org.apache.iotdb.db.qp.physical.crud.BatchInsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
@@ -59,6 +64,7 @@ public class StorageEngine implements IService {
 
   private static final Logger logger = LoggerFactory.getLogger(StorageEngine.class);
   private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+  private static final long TTL_CHECK_INTERVAL = 60 * 1000;
 
   /**
    * a folder (system/storage_groups/ by default) that persist system info. Each Storage Processor
@@ -77,6 +83,8 @@ public class StorageEngine implements IService {
     return INSTANCE;
   }
 
+  private ScheduledExecutorService ttlCheckThread;
+
   private StorageEngine() {
     systemDir = FilePathUtils.regularizePath(config.getSystemDir()) + "storage_groups";
     // create systemDir
@@ -86,17 +94,18 @@ public class StorageEngine implements IService {
       throw new StorageEngineFailureException("create system directory failed!");
     }
 
-    /**
+    /*
      * recover all storage group processors.
      */
     try {
-      List<String> storageGroups = MManager.getInstance().getAllStorageGroupNames();
-      for (String storageGroup : storageGroups) {
-        StorageGroupProcessor processor = new StorageGroupProcessor(systemDir, storageGroup);
-        logger.info("Storage Group Processor {} is recovered successfully", storageGroup);
-        processorMap.put(storageGroup, processor);
+      List<MNode> sgNodes = MManager.getInstance().getAllStorageGroups();
+      for (MNode storageGroup : sgNodes) {
+        StorageGroupProcessor processor = new StorageGroupProcessor(systemDir, storageGroup.getFullPath());
+        processor.setDataTTL(storageGroup.getDataTTL());
+        logger.info("Storage Group Processor {} is recovered successfully", storageGroup.getFullPath());
+        processorMap.put(storageGroup.getFullPath(), processor);
       }
-    } catch (ProcessorException | MetadataErrorException e) {
+    } catch (ProcessorException e) {
       logger.error("init a storage group processor failed. ", e);
       throw new StorageEngineFailureException(e);
     }
@@ -104,12 +113,32 @@ public class StorageEngine implements IService {
 
   @Override
   public void start() {
-    // nothing to be done
+    ttlCheckThread = Executors.newSingleThreadScheduledExecutor();
+    ttlCheckThread.scheduleAtFixedRate(this::checkTTL, TTL_CHECK_INTERVAL, TTL_CHECK_INTERVAL
+    ,TimeUnit.MILLISECONDS);
+  }
+
+  private void checkTTL() {
+    try {
+      for (StorageGroupProcessor processor : processorMap.values()) {
+        processor.checkFilesTTL();
+      }
+    } catch (ConcurrentModificationException e) {
+      // ignore
+    } catch (Exception e) {
+      logger.error("An error occurred when checking TTL", e);
+    }
   }
 
   @Override
   public void stop() {
     syncCloseAllProcessor();
+    ttlCheckThread.shutdownNow();
+    try {
+      ttlCheckThread.awaitTermination(30, TimeUnit.SECONDS);
+    } catch (InterruptedException e) {
+      logger.warn("TTL check thread still doesn't exit after 30s");
+    }
   }
 
   @Override
@@ -131,12 +160,13 @@ public class StorageEngine implements IService {
             logger.info("construct a processor instance, the storage group is {}, Thread is {}",
                 storageGroupName, Thread.currentThread().getId());
             processor = new StorageGroupProcessor(systemDir, storageGroupName);
+            processor.setDataTTL(MManager.getInstance().getNodeByPathWithCheck(storageGroupName).getDataTTL());
             processorMap.put(storageGroupName, processor);
           }
         }
       }
       return processor;
-    } catch (StorageGroupException | ProcessorException e) {
+    } catch (StorageGroupException | ProcessorException | PathErrorException e) {
       logger.error("Fail to get StorageGroupProcessor {}", storageGroupName, e);
       throw new StorageEngineException(e);
     }
@@ -157,7 +187,7 @@ public class StorageEngine implements IService {
    * @param insertPlan physical plan of insertion
    * @return true if and only if this insertion succeeds
    */
-  public boolean insert(InsertPlan insertPlan) throws StorageEngineException {
+  public boolean insert(InsertPlan insertPlan) throws ProcessorException {
 
     StorageGroupProcessor storageGroupProcessor;
     try {
@@ -166,14 +196,14 @@ public class StorageEngine implements IService {
       logger.warn("get StorageGroupProcessor of device {} failed, because {}",
           insertPlan.getDeviceId(),
           e.getMessage(), e);
-      throw new StorageEngineException(e);
+      throw new ProcessorException(e);
     }
 
     // TODO monitor: update statistics
     try {
       return storageGroupProcessor.insert(insertPlan);
     } catch (QueryProcessorException e) {
-      throw new StorageEngineException(e.getMessage());
+      throw new ProcessorException(e);
     }
   }
 
@@ -201,15 +231,6 @@ public class StorageEngine implements IService {
   }
 
   /**
-   * only for unit test
-   */
-  public void asyncFlushAndSealAllFiles() {
-    for (StorageGroupProcessor storageGroupProcessor : processorMap.values()) {
-      storageGroupProcessor.putAllWorkingTsFileProcessorIntoClosingList();
-    }
-  }
-
-  /**
    * flush command Sync asyncCloseOneProcessor all file node processors.
    */
   public void syncCloseAllProcessor() {
@@ -278,7 +299,7 @@ public class StorageEngine implements IService {
   }
 
   /**
-   * get all overlap tsfiles which are conflict with the appendFile.
+   * get all overlap TsFiles which are conflict with the appendFile.
    *
    * @param storageGroupName the seriesPath of storage group
    * @param appendFile the appended tsfile information
@@ -336,17 +357,17 @@ public class StorageEngine implements IService {
    */
   public synchronized boolean deleteAll() {
     logger.info("Start deleting all storage groups' timeseries");
-    try {
-      for (String storageGroup : MManager.getInstance().getAllStorageGroupNames()) {
-        this.deleteAllDataFilesInOneStorageGroup(storageGroup);
-      }
-    } catch (MetadataErrorException e) {
-      logger.error("delete storage groups failed.", e);
-      return false;
+    for (String storageGroup : MManager.getInstance().getAllStorageGroupNames()) {
+      this.deleteAllDataFilesInOneStorageGroup(storageGroup);
     }
     return true;
   }
 
+  public void setTTL(String storageGroup, long dataTTL) throws StorageEngineException {
+    StorageGroupProcessor storageGroupProcessor = getProcessor(storageGroup);
+    storageGroupProcessor.setDataTTL(dataTTL);
+  }
+
   public void deleteStorageGroup(String storageGroupName) {
     deleteAllDataFilesInOneStorageGroup(storageGroupName);
     StorageGroupProcessor processor = processorMap.remove(storageGroupName);
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/cache/DeviceMetaDataCache.java b/server/src/main/java/org/apache/iotdb/db/engine/cache/DeviceMetaDataCache.java
index 2320e73..1692443 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/cache/DeviceMetaDataCache.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/cache/DeviceMetaDataCache.java
@@ -65,9 +65,6 @@ public class DeviceMetaDataCache {
   private long chunkMetaDataSize = 0;
 
   private DeviceMetaDataCache(long memoryThreshold) {
-    if (!cacheEnable) {
-      return;
-    }
     lruCache = new LRULinkedHashMap<String, List<ChunkMetaData>>(memoryThreshold, true) {
       @Override
       protected long calEntrySize(String key, List<ChunkMetaData> value) {
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/cache/TsFileMetaDataCache.java b/server/src/main/java/org/apache/iotdb/db/engine/cache/TsFileMetaDataCache.java
index 33994e6..fd93b32 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/cache/TsFileMetaDataCache.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/cache/TsFileMetaDataCache.java
@@ -58,9 +58,6 @@ public class TsFileMetaDataCache {
   private long versionAndCreatebySize = 10;
 
   private TsFileMetaDataCache() {
-    if (!cacheEnable) {
-      return;
-    }
     cache = new LRULinkedHashMap<TsFileResource, TsFileMetaData>(MEMORY_THRESHOLD_IN_B, true) {
       @Override
       protected long calEntrySize(TsFileResource key, TsFileMetaData value) {
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
index c3d8cb8..2c6e5bd 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
@@ -153,12 +153,12 @@ public abstract class AbstractMemTable implements IMemTable {
 
   @Override
   public ReadOnlyMemChunk query(String deviceId, String measurement, TSDataType dataType,
-      Map<String, String> props) {
+      Map<String, String> props, long timeLowerBound) {
     TimeValuePairSorter sorter;
     if (!checkPath(deviceId, measurement)) {
       return null;
     } else {
-      long undeletedTime = findUndeletedTime(deviceId, measurement);
+      long undeletedTime = findUndeletedTime(deviceId, measurement, timeLowerBound);
       IWritableMemChunk memChunk = memTableMap.get(deviceId).get(measurement);
       IWritableMemChunk chunkCopy = new WritableMemChunk(dataType, memChunk.getTVList().clone());
       chunkCopy.setTimeOffset(undeletedTime);
@@ -168,7 +168,7 @@ public abstract class AbstractMemTable implements IMemTable {
   }
 
 
-  private long findUndeletedTime(String deviceId, String measurement) {
+  private long findUndeletedTime(String deviceId, String measurement, long timeLowerBound) {
     long undeletedTime = Long.MIN_VALUE;
     for (Modification modification : modifications) {
       if (modification instanceof Deletion) {
@@ -179,7 +179,7 @@ public abstract class AbstractMemTable implements IMemTable {
         }
       }
     }
-    return undeletedTime + 1;
+    return Math.max(undeletedTime + 1, timeLowerBound);
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
index 1d5b4c5..aeae931 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
@@ -58,7 +58,7 @@ public interface IMemTable {
   void insertBatch(BatchInsertPlan batchInsertPlan, List<Integer> indexes) throws QueryProcessorException;
 
   ReadOnlyMemChunk query(String deviceId, String measurement, TSDataType dataType,
-      Map<String, String> props);
+      Map<String, String> props, long timeLowerBound);
 
   /**
    * putBack all the memory resources.
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/merge/manage/MergeResource.java b/server/src/main/java/org/apache/iotdb/db/engine/merge/manage/MergeResource.java
index 941e572..f418cb6 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/merge/manage/MergeResource.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/merge/manage/MergeResource.java
@@ -19,6 +19,18 @@
 
 package org.apache.iotdb.db.engine.merge.manage;
 
+import static org.apache.iotdb.db.engine.merge.task.MergeTask.MERGE_SUFFIX;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 import org.apache.iotdb.db.engine.modification.Modification;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.query.reader.IPointReader;
@@ -36,16 +48,6 @@ import org.apache.iotdb.tsfile.write.chunk.ChunkWriterImpl;
 import org.apache.iotdb.tsfile.write.chunk.IChunkWriter;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 import org.apache.iotdb.tsfile.write.writer.RestorableTsFileIOWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-import static org.apache.iotdb.db.engine.merge.task.MergeTask.MERGE_SUFFIX;
 
 /**
  * MergeResource manages files and caches of readers, writers, MeasurementSchemas and
@@ -53,8 +55,6 @@ import static org.apache.iotdb.db.engine.merge.task.MergeTask.MERGE_SUFFIX;
  */
 public class MergeResource {
 
-  private static final Logger logger = LoggerFactory.getLogger(MergeResource.class);
-
   private List<TsFileResource> seqFiles;
   private List<TsFileResource> unseqFiles;
 
@@ -64,12 +64,28 @@ public class MergeResource {
   private Map<String, MeasurementSchema> measurementSchemaMap = new HashMap<>();
   private Map<MeasurementSchema, IChunkWriter> chunkWriterCache = new ConcurrentHashMap<>();
 
+  private long timeLowerBound = Long.MIN_VALUE;
+
   private boolean cacheDeviceMeta = false;
 
   public MergeResource(List<TsFileResource> seqFiles, List<TsFileResource> unseqFiles) {
-    this.seqFiles = seqFiles.stream().filter(TsFileResource::isClosed).collect(Collectors.toList());
+    this.seqFiles =
+        seqFiles.stream().filter(this::filterResource).collect(Collectors.toList());
     this.unseqFiles =
-        unseqFiles.stream().filter(TsFileResource::isClosed).collect(Collectors.toList());
+        unseqFiles.stream().filter(this::filterResource).collect(Collectors.toList());
+  }
+
+  private boolean filterResource(TsFileResource res) {
+    return res.isClosed() && !res.isDeleted() && res.stillLives(timeLowerBound);
+  }
+
+  public MergeResource(List<TsFileResource> seqFiles, List<TsFileResource> unseqFiles,
+      long timeLowerBound) {
+    this.timeLowerBound = timeLowerBound;
+    this.seqFiles =
+        seqFiles.stream().filter(this::filterResource).collect(Collectors.toList());
+    this.unseqFiles =
+        unseqFiles.stream().filter(this::filterResource).collect(Collectors.toList());
   }
 
   public void clear() throws IOException {
@@ -230,10 +246,6 @@ public class MergeResource {
     this.unseqFiles = unseqFiles;
   }
 
-  public Map<String, MeasurementSchema> getMeasurementSchemaMap() {
-    return measurementSchemaMap;
-  }
-
   public void removeOutdatedSeqReaders() throws IOException {
     Iterator<Entry<TsFileResource, TsFileSequenceReader>> entryIterator =
         fileReaderCache.entrySet().iterator();
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
index 39bbb02..93a7896 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
@@ -158,6 +158,10 @@ public class MergeTask implements Callable<Void> {
     for (TsFileResource seqFile : resource.getSeqFiles()) {
       File mergeFile = new File(seqFile.getFile().getPath() + MERGE_SUFFIX);
       mergeFile.delete();
+      seqFile.setMerging(false);
+    }
+    for (TsFileResource unseqFile : resource.getUnseqFiles()) {
+      unseqFile.setMerging(false);
     }
 
     File logFile = new File(storageGroupSysDir, MergeLogger.MERGE_LOG_NAME);
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/querycontext/QueryDataSource.java b/server/src/main/java/org/apache/iotdb/db/engine/querycontext/QueryDataSource.java
index 2eebde2..82fb622 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/querycontext/QueryDataSource.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/querycontext/QueryDataSource.java
@@ -23,12 +23,20 @@ import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.tsfile.read.common.Path;
 
 import java.util.List;
+import org.apache.iotdb.tsfile.read.filter.TimeFilter;
+import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+import org.apache.iotdb.tsfile.read.filter.operator.AndFilter;
 
 public class QueryDataSource {
   private Path seriesPath;
   private List<TsFileResource> seqResources;
   private List<TsFileResource> unseqResources;
 
+  /**
+   * data older than currentTime - dataTTL should be ignored.
+   */
+  private long dataTTL = Long.MAX_VALUE;
+
   public QueryDataSource(Path seriesPath, List<TsFileResource> seqResources, List<TsFileResource> unseqResources) {
     this.seriesPath = seriesPath;
     this.seqResources = seqResources;
@@ -46,4 +54,28 @@ public class QueryDataSource {
   public List<TsFileResource> getUnseqResources() {
     return unseqResources;
   }
+
+  public long getDataTTL() {
+    return dataTTL;
+  }
+
+  public void setDataTTL(long dataTTL) {
+    this.dataTTL = dataTTL;
+  }
+
+  /**
+   *
+   * @return an updated time filter concerning TTL
+   */
+  public Filter updateTimeFilter(Filter timeFilter) {
+    if (dataTTL != Long.MAX_VALUE) {
+      if (timeFilter != null) {
+        timeFilter = new AndFilter(timeFilter, TimeFilter.gtEq(System.currentTimeMillis() -
+            dataTTL));
+      } else {
+        timeFilter = TimeFilter.gtEq(System.currentTimeMillis() - dataTTL);
+      }
+    }
+    return timeFilter;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
index 4260dd4..e85f2fc 100755
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -60,6 +61,7 @@ import org.apache.iotdb.db.engine.version.VersionController;
 import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.apache.iotdb.db.exception.MergeException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
+import org.apache.iotdb.db.exception.OutOfTTLException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StorageGroupProcessorException;
 import org.apache.iotdb.db.exception.TsFileProcessorException;
@@ -71,6 +73,7 @@ import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.JobFileManager;
 import org.apache.iotdb.db.utils.CopyOnReadLinkedList;
+import org.apache.iotdb.db.utils.TestOnly;
 import org.apache.iotdb.db.writelog.recover.TsFileRecoverPerformer;
 import org.apache.iotdb.rpc.TSStatusCode;
 import org.apache.iotdb.tsfile.file.metadata.ChunkMetaData;
@@ -86,6 +89,7 @@ import org.apache.iotdb.tsfile.write.schema.Schema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /**
  * For sequence data, a StorageGroupProcessor has some TsFileProcessors, in which there is only one
  * TsFileProcessor in the working status. <br/>
@@ -108,7 +112,7 @@ import org.slf4j.LoggerFactory;
  */
 public class StorageGroupProcessor {
 
-  private static final String MERGING_MODIFICAITON_FILE_NAME = "merge.mods";
+  private static final String MERGING_MODIFICATION_FILE_NAME = "merge.mods";
   private static final Logger logger = LoggerFactory.getLogger(StorageGroupProcessor.class);
   /**
    * a read write lock for guaranteeing concurrent safety when accessing all fields in this class
@@ -118,7 +122,7 @@ public class StorageGroupProcessor {
    */
   private final ReadWriteLock insertLock = new ReentrantReadWriteLock();
   /**
-   *
+   * closeStorageGroupCondition is used to wait for all currently closing TsFiles to be done.
    */
   private final Object closeStorageGroupCondition = new Object();
   /**
@@ -180,6 +184,12 @@ public class StorageGroupProcessor {
   private LinkedList<String> lruForSensorUsedInQuery = new LinkedList<>();
   private static final int MAX_CACHE_SENSORS = 5000;
 
+  /**
+   * when the data in a storage group is older than dataTTL, it is considered invalid and will
+   * be eventually removed.
+   */
+  private long dataTTL = Long.MAX_VALUE;
+
   private FSFactory fsFactory = FSFactoryProducer.getFSFactory();
 
   public StorageGroupProcessor(String systemInfoDir, String storageGroupName)
@@ -221,8 +231,8 @@ public class StorageGroupProcessor {
       recoverUnseqFiles(unseqTsFiles);
 
       String taskName = storageGroupName + "-" + System.currentTimeMillis();
-      File mergingMods = SystemFileFactory.INSTANCE
-          .getFile(storageGroupSysDir, MERGING_MODIFICAITON_FILE_NAME);
+      File mergingMods = SystemFileFactory.INSTANCE.getFile(storageGroupSysDir,
+          MERGING_MODIFICATION_FILE_NAME);
       if (mergingMods.exists()) {
         mergingModification = new ModificationFile(mergingMods.getPath());
       }
@@ -245,7 +255,7 @@ public class StorageGroupProcessor {
     }
   }
 
-  private List<TsFileResource> getAllFiles(List<String> folders) throws IOException {
+  private List<TsFileResource> getAllFiles(List<String> folders) {
     List<File> tsFiles = new ArrayList<>();
     for (String baseDir : folders) {
       File fileFolder = fsFactory.getFile(baseDir, storageGroupName);
@@ -305,17 +315,19 @@ public class StorageGroupProcessor {
     }
   }
 
-  // TsFileNameComparator compares TsFiles by the version number in its name
   // ({systemTime}-{versionNum}-{mergeNum}.tsfile)
   private int compareFileName(File o1, File o2) {
     String[] items1 = o1.getName().replace(TSFILE_SUFFIX, "")
         .split(IoTDBConstant.TSFILE_NAME_SEPARATOR);
     String[] items2 = o2.getName().replace(TSFILE_SUFFIX, "")
         .split(IoTDBConstant.TSFILE_NAME_SEPARATOR);
-    if (Long.valueOf(items1[0]) - Long.valueOf(items2[0]) == 0) {
-      return Long.compare(Long.valueOf(items1[1]), Long.valueOf(items2[1]));
+    long ver1 = Long.parseLong(items1[0]);
+    long ver2 = Long.parseLong(items2[0]);
+    int cmp = Long.compare(ver1, ver2);
+    if (cmp == 0) {
+      return Long.compare(Long.parseLong(items1[1]), Long.parseLong(items2[1]));
     } else {
-      return Long.compare(Long.valueOf(items1[0]), Long.valueOf(items2[0]));
+      return cmp;
     }
   }
 
@@ -323,11 +335,11 @@ public class StorageGroupProcessor {
     List<MeasurementSchema> columnSchemaList;
     columnSchemaList = MManager.getInstance().getSchemaForStorageGroup(storageGroupName);
 
-    Schema schema = new Schema();
+    Schema newSchema = new Schema();
     for (MeasurementSchema measurementSchema : columnSchemaList) {
-      schema.registerMeasurement(measurementSchema);
+      newSchema.registerMeasurement(measurementSchema);
     }
-    return schema;
+    return newSchema;
   }
 
 
@@ -346,6 +358,10 @@ public class StorageGroupProcessor {
   }
 
   public boolean insert(InsertPlan insertPlan) throws QueryProcessorException {
+    // reject insertions that are out of ttl
+    if (!checkTTL(insertPlan.getTime())) {
+     throw new OutOfTTLException(insertPlan.getTime(), (System.currentTimeMillis() - dataTTL));
+    }
     writeLock();
     try {
       // init map
@@ -371,10 +387,16 @@ public class StorageGroupProcessor {
       List<Integer> sequenceIndexes = new ArrayList<>();
       List<Integer> unsequenceIndexes = new ArrayList<>();
 
+      long lastFlushTime = latestFlushedTimeForEachDevice.get(batchInsertPlan.getDeviceId());
       for (int i = 0; i < batchInsertPlan.getRowCount(); i++) {
+        long currTime = batchInsertPlan.getTimes()[i];
+        // skip points that do not satisfy TTL
+        if (!checkTTL(currTime)) {
+          results[i] = TSStatusCode.OUT_OF_TTL_ERROR.getStatusCode();
+          continue;
+        }
         results[i] = TSStatusCode.SUCCESS_STATUS.getStatusCode();
-        if (batchInsertPlan.getTimes()[i] > latestFlushedTimeForEachDevice
-            .get(batchInsertPlan.getDeviceId())) {
+        if (currTime > lastFlushTime) {
           sequenceIndexes.add(i);
         } else {
           unsequenceIndexes.add(i);
@@ -394,6 +416,15 @@ public class StorageGroupProcessor {
     }
   }
 
+  /**
+   *
+   * @param time
+   * @return whether the given time falls in ttl
+   */
+  private boolean checkTTL(long time) {
+    return dataTTL == Long.MAX_VALUE || (System.currentTimeMillis() - time) <= dataTTL;
+  }
+
   private void insertBatchToTsFileProcessor(BatchInsertPlan batchInsertPlan,
       List<Integer> indexes, boolean sequence, Integer[] results) throws QueryProcessorException {
 
@@ -569,16 +600,8 @@ public class StorageGroupProcessor {
       }
       List<String> folder = DirectoryManager.getInstance().getAllSequenceFileFolders();
       folder.addAll(DirectoryManager.getInstance().getAllUnSequenceFileFolders());
-      for (String tsfilePath : folder) {
-        File storageGroupFolder = fsFactory.getFile(tsfilePath, storageGroupName);
-        if (storageGroupFolder.exists()) {
-          try {
-            FileUtils.deleteDirectory(storageGroupFolder);
-          } catch (IOException e) {
-            logger.error("Delete tsfiles failed", e);
-          }
-        }
-      }
+      deleteAllSGFolders(folder);
+
       this.workSequenceTsFileProcessor = null;
       this.workUnSequenceTsFileProcessor = null;
       this.sequenceFileList.clear();
@@ -592,6 +615,81 @@ public class StorageGroupProcessor {
     }
   }
 
+  private void deleteAllSGFolders(List<String> folder) {
+    for (String tsfilePath : folder) {
+      File storageGroupFolder = fsFactory.getFile(tsfilePath, storageGroupName);
+      if (storageGroupFolder.exists()) {
+        try {
+          FileUtils.deleteDirectory(storageGroupFolder);
+        } catch (IOException e) {
+          logger.error("Delete TsFiles failed", e);
+        }
+      }
+    }
+  }
+
+  /**
+   * Iterate each TsFile and try to lock and remove those out of TTL.
+   */
+  public synchronized void checkFilesTTL() {
+    if (dataTTL == Long.MAX_VALUE) {
+      logger.debug("{}: TTL not set, ignore the check", storageGroupName);
+      return;
+    }
+    long timeLowerBound = System.currentTimeMillis() - dataTTL;
+    if (logger.isDebugEnabled()) {
+      logger.debug("{}: TTL removing files before {}", storageGroupName, new Date(timeLowerBound));
+    }
+    // copy to avoid concurrent modification of deletion
+    List<TsFileResource> seqFiles = new ArrayList<>(sequenceFileList);
+    List<TsFileResource> unseqFiles = new ArrayList<>(unSequenceFileList);
+
+    for (TsFileResource tsFileResource : seqFiles) {
+      checkFileTTL(tsFileResource, timeLowerBound, true);
+    }
+    for (TsFileResource tsFileResource : unseqFiles) {
+      checkFileTTL(tsFileResource, timeLowerBound, false);
+    }
+  }
+
+  private void checkFileTTL(TsFileResource resource, long timeLowerBound, boolean isSeq) {
+    if (resource.isMerging() || !resource.isClosed()
+        || !resource.isDeleted() && resource.stillLives(timeLowerBound)) {
+      return;
+    }
+
+    writeLock();
+    try {
+      // prevent new merges and queries from choosing this file
+      resource.setDeleted(true);
+      // the file may be chosen for merge after the last check and before writeLock()
+      // double check to ensure the file is not used by a merge
+      if (resource.isMerging()) {
+        return;
+      }
+      // ensure that the file is not used by any queries
+      if (resource.getMergeQueryLock().writeLock().tryLock()) {
+        try {
+          // physical removal
+          resource.remove();
+          if (logger.isInfoEnabled()) {
+            logger.info("Removed a file {} before {} by ttl ({}ms)", resource.getFile().getPath(),
+                new Date(timeLowerBound), dataTTL);
+          }
+          if (isSeq) {
+            sequenceFileList.remove(resource);
+          } else {
+            unSequenceFileList.remove(resource);
+          }
+        } finally {
+          resource.getMergeQueryLock().writeLock().unlock();
+        }
+      }
+    } finally {
+      writeUnlock();
+    }
+  }
+
   /**
    * This method will be blocked until all tsfile processors are closed.
    */
@@ -650,6 +748,7 @@ public class StorageGroupProcessor {
       if (filePathsManager != null) {
         filePathsManager.addUsedFilesForGivenJob(context.getJobId(), dataSource);
       }
+      dataSource.setDataTTL(dataTTL);
       return dataSource;
     } finally {
       insertLock.readLock().unlock();
@@ -698,35 +797,55 @@ public class StorageGroupProcessor {
     TSDataType dataType = mSchema.getType();
 
     List<TsFileResource> tsfileResourcesForQuery = new ArrayList<>();
+    long timeLowerBound = dataTTL != Long.MAX_VALUE ? System.currentTimeMillis() - dataTTL : Long
+        .MIN_VALUE;
+    context.setQueryTimeLowerBound(timeLowerBound);
+
     for (TsFileResource tsFileResource : tsFileResources) {
       // TODO: try filtering files if the query contains time filter
-      if (!tsFileResource.containsDevice(deviceId)) {
+      if (!testResourceDevice(tsFileResource, deviceId)) {
         continue;
       }
-      if (!tsFileResource.getStartTimeMap().isEmpty()) {
-        closeQueryLock.readLock().lock();
-        try {
-          if (tsFileResource.isClosed()) {
-            tsfileResourcesForQuery.add(tsFileResource);
-          } else {
-            // left: in-memory data, right: meta of disk data
-            Pair<ReadOnlyMemChunk, List<ChunkMetaData>> pair;
-            pair = tsFileResource
-                .getUnsealedFileProcessor()
-                .query(deviceId, measurementId, dataType, mSchema.getProps(), context);
-            tsfileResourcesForQuery
-                .add(new TsFileResource(tsFileResource.getFile(),
-                    tsFileResource.getStartTimeMap(),
-                    tsFileResource.getEndTimeMap(), pair.left, pair.right));
-          }
-        } finally {
-          closeQueryLock.readLock().unlock();
+      closeQueryLock.readLock().lock();
+
+      try {
+        if (tsFileResource.isClosed()) {
+          tsfileResourcesForQuery.add(tsFileResource);
+        } else {
+          // left: in-memory data, right: meta of disk data
+          Pair<ReadOnlyMemChunk, List<ChunkMetaData>> pair;
+          pair = tsFileResource
+              .getUnsealedFileProcessor()
+              .query(deviceId, measurementId, dataType, mSchema.getProps(), context);
+          tsfileResourcesForQuery
+              .add(new TsFileResource(tsFileResource.getFile(),
+                  tsFileResource.getStartTimeMap(),
+                  tsFileResource.getEndTimeMap(), pair.left, pair.right));
         }
+      } finally {
+        closeQueryLock.readLock().unlock();
       }
     }
     return tsfileResourcesForQuery;
   }
 
+  /**
+   *
+   * @param tsFileResource
+   * @param deviceId
+   * @return true if the device is contained in the TsFile and it lives beyond TTL
+   */
+  private boolean testResourceDevice(TsFileResource tsFileResource, String deviceId) {
+    if (!tsFileResource.containsDevice(deviceId)) {
+      return false;
+    }
+    if (dataTTL != Long.MAX_VALUE) {
+      Long deviceEndTime = tsFileResource.getEndTimeMap().get(deviceId);
+      return deviceEndTime == null || checkTTL(deviceEndTime);
+    }
+    return true;
+  }
+
 
   /**
    * Delete data whose timestamp <= 'timestamp' and belongs to the timeseries
@@ -837,7 +956,7 @@ public class StorageGroupProcessor {
    * put the memtable back to the MemTablePool and make the metadata in writer visible
    */
   // TODO please consider concurrency with query and insert method.
-  public void closeUnsealedTsFileProcessor(
+  private void closeUnsealedTsFileProcessor(
       TsFileProcessor tsFileProcessor) throws TsFileProcessorException {
     closeQueryLock.writeLock().lock();
     try {
@@ -873,7 +992,9 @@ public class StorageGroupProcessor {
       }
 
       long budget = IoTDBDescriptor.getInstance().getConfig().getMergeMemoryBudget();
-      MergeResource mergeResource = new MergeResource(sequenceFileList, unSequenceFileList);
+      long timeLowerBound = System.currentTimeMillis() - dataTTL;
+      MergeResource mergeResource = new MergeResource(sequenceFileList, unSequenceFileList, timeLowerBound);
+
       IMergeFileSelector fileSelector = getMergeFileSelector(budget, mergeResource);
       try {
         List[] mergeFiles = fileSelector.select();
@@ -889,11 +1010,18 @@ public class StorageGroupProcessor {
         // cached during selection
         mergeResource.setCacheDeviceMeta(true);
 
+        for (TsFileResource tsFileResource : mergeResource.getSeqFiles()) {
+          tsFileResource.setMerging(true);
+        }
+        for (TsFileResource tsFileResource : mergeResource.getUnseqFiles()) {
+          tsFileResource.setMerging(true);
+        }
+
         MergeTask mergeTask = new MergeTask(mergeResource, storageGroupSysDir.getPath(),
             this::mergeEndAction, taskName, fullMerge, fileSelector.getConcurrentMergeNum(),
             storageGroupName);
         mergingModification = new ModificationFile(
-            storageGroupSysDir + File.separator + MERGING_MODIFICAITON_FILE_NAME);
+            storageGroupSysDir + File.separator + MERGING_MODIFICATION_FILE_NAME);
         MergeManager.getINSTANCE().submitMainTask(mergeTask);
         if (logger.isInfoEnabled()) {
           logger.info("{} submits a merge task {}, merging {} seqFiles, {} unseqFiles",
@@ -922,17 +1050,7 @@ public class StorageGroupProcessor {
     }
   }
 
-  protected void mergeEndAction(List<TsFileResource> seqFiles, List<TsFileResource> unseqFiles,
-      File mergeLog) {
-    logger.info("{} a merge task is ending...", storageGroupName);
-
-    if (unseqFiles.isEmpty()) {
-      // merge runtime exception arose, just end this merge
-      isMerging = false;
-      logger.info("{} a merge task abnormally ends", storageGroupName);
-      return;
-    }
-
+  private void removeUnseqFiles(List<TsFileResource> unseqFiles) {
     mergeLock.writeLock().lock();
     try {
       unSequenceFileList.removeAll(unseqFiles);
@@ -948,39 +1066,61 @@ public class StorageGroupProcessor {
         unseqFile.getMergeQueryLock().writeLock().unlock();
       }
     }
+  }
+
+  private void updateMergeModification(TsFileResource seqFile) {
+    seqFile.getMergeQueryLock().writeLock().lock();
+    try {
+      // remove old modifications and write modifications generated during merge
+      seqFile.removeModFile();
+      if (mergingModification != null) {
+        for (Modification modification : mergingModification.getModifications()) {
+          seqFile.getModFile().write(modification);
+        }
+      }
+    } catch (IOException e) {
+      logger.error("{} cannot clean the ModificationFile of {} after merge", storageGroupName,
+          seqFile.getFile(), e);
+    } finally {
+      seqFile.getMergeQueryLock().writeLock().unlock();
+    }
+  }
+
+  private void removeMergingModification() {
+    try {
+      if (mergingModification != null) {
+        mergingModification.remove();
+        mergingModification = null;
+      }
+    } catch (IOException e) {
+      logger.error("{} cannot remove merging modification ", storageGroupName, e);
+    }
+  }
+
+  protected void mergeEndAction(List<TsFileResource> seqFiles, List<TsFileResource> unseqFiles,
+      File mergeLog) {
+    logger.info("{} a merge task is ending...", storageGroupName);
+
+    if (unseqFiles.isEmpty()) {
+      // merge runtime exception arose, just end this merge
+      isMerging = false;
+      logger.info("{} a merge task abnormally ends", storageGroupName);
+      return;
+    }
+
+    removeUnseqFiles(unseqFiles);
 
     for (int i = 0; i < seqFiles.size(); i++) {
       TsFileResource seqFile = seqFiles.get(i);
-      seqFile.getMergeQueryLock().writeLock().lock();
       mergeLock.writeLock().lock();
       try {
-        logger.debug("{} is updating the {} merged file's modification file", storageGroupName, i);
-        try {
-          // remove old modifications and write modifications generated during merge
-          seqFile.removeModFile();
-          if (mergingModification != null) {
-            for (Modification modification : mergingModification.getModifications()) {
-              seqFile.getModFile().write(modification);
-            }
-          }
-        } catch (IOException e) {
-          logger.error("{} cannot clean the ModificationFile of {} after merge", storageGroupName,
-              seqFile.getFile(), e);
-        }
+        updateMergeModification(seqFile);
         if (i == seqFiles.size() - 1) {
-          try {
-            if (mergingModification != null) {
-              mergingModification.remove();
-              mergingModification = null;
-            }
-          } catch (IOException e) {
-            logger.error("{} cannot remove merging modification ", storageGroupName, e);
-          }
+          removeMergingModification();
           isMerging = false;
+          mergeLog.delete();
         }
       } finally {
-        mergeLog.delete();
-        seqFile.getMergeQueryLock().writeLock().unlock();
         mergeLock.writeLock().unlock();
       }
     }
@@ -1031,7 +1171,8 @@ public class StorageGroupProcessor {
     }
     long targetTsFileTime = Long.parseLong(
         tsFileResource.getFile().getName().split(IoTDBConstant.TSFILE_NAME_SEPARATOR)[0]);
-    int s = 0, e = sequenceFileList.size() - 1;
+    int s = 0;
+    int e = sequenceFileList.size() - 1;
     while (s <= e) {
       int m = s + ((e - s) >> 1);
       long currentTsFileTime = Long.parseLong(sequenceFileList.get(m).getFile().getName()
@@ -1182,24 +1323,32 @@ public class StorageGroupProcessor {
     }
   }
 
+
   public TsFileProcessor getWorkSequenceTsFileProcessor() {
     return workSequenceTsFileProcessor;
   }
 
+  @FunctionalInterface
+  public interface CloseTsFileCallBack {
+
+    void call(TsFileProcessor caller) throws TsFileProcessorException, IOException;
+  }
+
+  public void setDataTTL(long dataTTL) {
+    this.dataTTL = dataTTL;
+    checkFilesTTL();
+  }
+
+  @TestOnly
   public List<TsFileResource> getSequenceFileList() {
     return sequenceFileList;
   }
 
+  @TestOnly
   public List<TsFileResource> getUnSequenceFileList() {
     return unSequenceFileList;
   }
 
-  @FunctionalInterface
-  public interface CloseTsFileCallBack {
-
-    void call(TsFileProcessor caller) throws TsFileProcessorException, IOException;
-  }
-
   private enum LoadTsFileType {
     LOAD_SEQUENCE, LOAD_UNSEQUENCE
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
index 44a1f91..96db668 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
@@ -586,13 +586,14 @@ public class TsFileProcessor {
           continue;
         }
         ReadOnlyMemChunk memChunk = flushingMemTable
-            .query(deviceId, measurementId, dataType, props);
+            .query(deviceId, measurementId, dataType, props, context.getQueryTimeLowerBound());
         if (memChunk != null) {
           memSeriesLazyMerger.addMemSeries(memChunk);
         }
       }
       if (workMemTable != null) {
-        ReadOnlyMemChunk memChunk = workMemTable.query(deviceId, measurementId, dataType, props);
+        ReadOnlyMemChunk memChunk = workMemTable.query(deviceId, measurementId, dataType, props,
+            context.getQueryTimeLowerBound());
         if (memChunk != null) {
           memSeriesLazyMerger.addMemSeries(memChunk);
         }
@@ -611,6 +612,8 @@ public class TsFileProcessor {
       QueryUtils.modifyChunkMetaData(chunkMetaDataList,
           modifications);
 
+      chunkMetaDataList.removeIf(context::chunkNotSatisfy);
+
       return new Pair<>(timeValuePairSorter, chunkMetaDataList);
     } finally {
       flushQueryLock.readLock().unlock();
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileResource.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileResource.java
index 3e8b602..2ab19cb 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileResource.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileResource.java
@@ -35,10 +35,11 @@ import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
 public class TsFileResource {
 
+  // tsfile
   private File file;
 
   public static final String RESOURCE_SUFFIX = ".resource";
-  public static final String TEMP_SUFFIX = ".temp";
+  static final String TEMP_SUFFIX = ".temp";
 
   /**
    * device -> start time
@@ -55,12 +56,14 @@ public class TsFileResource {
   private ModificationFile modFile;
 
   private volatile boolean closed = false;
+  private volatile boolean deleted = false;
+  private volatile boolean isMerging = false;
 
   /**
    * Chunk metadata list of unsealed tsfile. Only be set in a temporal TsFileResource in a query
    * process.
    */
-  private List<ChunkMetaData> chunkMetaDatas;
+  private List<ChunkMetaData> chunkMetaDataList;
 
   /**
    * Mem chunk data. Only be set in a temporal TsFileResource in a query process.
@@ -98,11 +101,11 @@ public class TsFileResource {
       Map<String, Long> startTimeMap,
       Map<String, Long> endTimeMap,
       ReadOnlyMemChunk readOnlyMemChunk,
-      List<ChunkMetaData> chunkMetaDatas) {
+      List<ChunkMetaData> chunkMetaDataList) {
     this.file = file;
     this.startTimeMap = startTimeMap;
     this.endTimeMap = endTimeMap;
-    this.chunkMetaDatas = chunkMetaDatas;
+    this.chunkMetaDataList = chunkMetaDataList;
     this.readOnlyMemChunk = readOnlyMemChunk;
   }
 
@@ -170,8 +173,8 @@ public class TsFileResource {
       endTimeMap.put(device, time);
   }
 
-  public List<ChunkMetaData> getChunkMetaDatas() {
-    return chunkMetaDatas;
+  public List<ChunkMetaData> getChunkMetaDataList() {
+    return chunkMetaDataList;
   }
 
   public ReadOnlyMemChunk getReadOnlyMemChunk() {
@@ -205,10 +208,6 @@ public class TsFileResource {
     return startTimeMap;
   }
 
-  public void setEndTimeMap(Map<String, Long> endTimeMap) {
-    this.endTimeMap = endTimeMap;
-  }
-
   public Map<String, Long> getEndTimeMap() {
     return endTimeMap;
   }
@@ -224,7 +223,7 @@ public class TsFileResource {
       modFile = null;
     }
     processor = null;
-    chunkMetaDatas = null;
+    chunkMetaDataList = null;
   }
 
   public TsFileProcessor getUnsealedFileProcessor() {
@@ -271,4 +270,37 @@ public class TsFileResource {
   public void setClosed(boolean closed) {
     this.closed = closed;
   }
+
+  public boolean isDeleted() {
+    return deleted;
+  }
+
+  public void setDeleted(boolean deleted) {
+    this.deleted = deleted;
+  }
+
+  public boolean isMerging() {
+    return isMerging;
+  }
+
+  public void setMerging(boolean merging) {
+    isMerging = merging;
+  }
+
+  /**
+   * check if any of the device lives over the given time bound
+   * @param timeLowerBound
+   */
+  public boolean stillLives(long timeLowerBound) {
+    if (timeLowerBound == Long.MAX_VALUE) {
+      return true;
+    }
+    for (long endTime : endTimeMap.values()) {
+      // the file cannot be deleted if any device still lives
+      if (endTime >= timeLowerBound) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/server/src/main/java/org/apache/iotdb/db/exception/NotStorageGroupException.java
similarity index 71%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
copy to server/src/main/java/org/apache/iotdb/db/exception/NotStorageGroupException.java
index dd27fc5..6fb1957 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/server/src/main/java/org/apache/iotdb/db/exception/NotStorageGroupException.java
@@ -15,22 +15,14 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.jdbc;
-
-import java.sql.SQLException;
-
-public class IoTDBSQLException extends SQLException {
+package org.apache.iotdb.db.exception;
 
-  private static final long serialVersionUID = -3306001287342258977L;
+public class NotStorageGroupException extends PathErrorException {
 
-  public IoTDBSQLException(String reason) {
-    super(reason);
+  public NotStorageGroupException(String path) {
+    super(String.format("%s is not a storage group", path));
   }
-
-  public IoTDBSQLException(Throwable cause) {
-    super(cause);
-  }
-
-}
+}
\ No newline at end of file
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/server/src/main/java/org/apache/iotdb/db/exception/OutOfTTLException.java
similarity index 66%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
copy to server/src/main/java/org/apache/iotdb/db/exception/OutOfTTLException.java
index dd27fc5..b9af237 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/server/src/main/java/org/apache/iotdb/db/exception/OutOfTTLException.java
@@ -15,22 +15,18 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.jdbc;
-
-import java.sql.SQLException;
+package org.apache.iotdb.db.exception;
 
-public class IoTDBSQLException extends SQLException {
+import java.util.Date;
+import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 
-  private static final long serialVersionUID = -3306001287342258977L;
+public class OutOfTTLException extends QueryProcessorException {
 
-  public IoTDBSQLException(String reason) {
-    super(reason);
+  public OutOfTTLException(long insertionTime, long timeLowerBound) {
+    super(String.format("Insertion time [%s] is less than ttl time bound [%s]",
+        new Date(insertionTime), new Date(timeLowerBound)));
   }
-
-  public IoTDBSQLException(Throwable cause) {
-    super(cause);
-  }
-
-}
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java b/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
index cbe6ea6..06501e6 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
@@ -91,7 +91,7 @@ public class MGraph implements Serializable {
   /**
    * Add a deviceId to Metadata Tree.
    */
-  public MNode addDeviceIdToMTree(String deviceId) throws PathErrorException {
+  MNode addDeviceIdToMTree(String deviceId) throws PathErrorException {
     return mtree.addDeviceId(deviceId);
   }
 
@@ -193,7 +193,7 @@ public class MGraph implements Serializable {
    *
    * @return A HashMap whose Keys are separated by the storage file name.
    */
-  HashMap<String, ArrayList<String>> getAllPathGroupByFilename(String path)
+  HashMap<String, List<String>> getAllPathGroupByStorageGroup(String path)
       throws PathErrorException {
     String rootName = path.trim().split(DOUB_SEPARATOR)[0];
     if (mtree.getRoot().getName().equals(rootName)) {
@@ -205,6 +205,10 @@ public class MGraph implements Serializable {
     throw new PathErrorException(TIME_SERIES_INCORRECT + rootName);
   }
 
+  List<MNode> getAllStorageGroupNodes() {
+    return mtree.getAllStorageGroupNodes();
+  }
+
   /**
    * function for getting all timeseries paths under the given seriesPath.
    */
@@ -259,8 +263,8 @@ public class MGraph implements Serializable {
     return new Metadata(deviceIdMap);
   }
 
-  Set<String> getAllStorageGroup() {
-    return mtree.getAllStorageGroup();
+  List<String> getAllStorageGroupNames() {
+    return mtree.getAllStorageGroupList();
   }
 
   Set<String> getAllDevices() throws SQLException {
@@ -324,14 +328,14 @@ public class MGraph implements Serializable {
     return mtree.getStorageGroupNameByPath(node, path);
   }
 
-  boolean checkFileNameByPath(String path) {
+  boolean checkStorageGroupByPath(String path) {
     return mtree.checkFileNameByPath(path);
   }
 
   /**
    * Get all file names for given seriesPath
    */
-  List<String> getAllFileNamesByPath(String path) throws PathErrorException {
+  List<String> getAllStorageGroupNamesByPath(String path) throws PathErrorException {
     return mtree.getAllFileNamesByPath(path);
   }
 
@@ -347,20 +351,11 @@ public class MGraph implements Serializable {
   }
 
   MNode getNodeByPath(String path) throws PathErrorException {
-    return mtree.getNodeByPath(path);
+    return mtree.getNode(path);
   }
 
   MNode getNodeByPathWithCheck(String path) throws PathErrorException, StorageGroupException {
-    return mtree.getNodeByPathWithFileLevelCheck(path);
-  }
-
-  /**
-   * Extract the deviceId from given seriesPath.
-   *
-   * @return String represents the deviceId
-   */
-  public String getDeviceTypeByPath(String path) throws PathErrorException {
-    return mtree.getDeviceTypeByPath(path);
+      return mtree.getNodeByPathWithStorageGroupCheck(path);
   }
 
   /**
@@ -395,8 +390,8 @@ public class MGraph implements Serializable {
   /**
    * combine multiple metadata in string format
    */
-  static String combineMetadataInStrings(String[] metadatas) {
-    return MTree.combineMetadataInStrings(metadatas);
+  static String combineMetadataInStrings(String[] metadataArray) {
+    return MTree.combineMetadataInStrings(metadataArray);
   }
 
   /**
@@ -404,9 +399,9 @@ public class MGraph implements Serializable {
    */
   Map<String, Integer> countSeriesNumberInEachStorageGroup() throws PathErrorException {
     Map<String, Integer> res = new HashMap<>();
-    Set<String> storageGroups = this.getAllStorageGroup();
+    List<String> storageGroups = this.getAllStorageGroupNames();
     for (String sg : storageGroups) {
-      MNode node = mtree.getNodeByPath(sg);
+      MNode node = mtree.getNode(sg);
       res.put(sg, node.getLeafCount());
     }
     return res;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 320ed8a..e6d255c 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -40,6 +40,7 @@ import org.apache.iotdb.db.conf.adapter.IoTDBConfigDynamicAdapter;
 import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.exception.ConfigAdjusterException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
+import org.apache.iotdb.db.exception.NotStorageGroupException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.monitor.MonitorConstants;
@@ -215,9 +216,9 @@ public class MManager {
           }
         }
 
-        addPathToMTree(new Path(args[1]), TSDataType.deserialize(Short.valueOf(args[2])),
-            TSEncoding.deserialize(Short.valueOf(args[3])),
-            CompressionType.deserialize(Short.valueOf(args[4])),
+        addPathToMTree(new Path(args[1]), TSDataType.deserialize(Short.parseShort(args[2])),
+            TSEncoding.deserialize(Short.parseShort(args[3])),
+            CompressionType.deserialize(Short.parseShort(args[4])),
             props);
         break;
       case MetadataOperationType.DELETE_PATH_FROM_MTREE:
@@ -248,6 +249,9 @@ public class MManager {
       case MetadataOperationType.UNLINK_MNODE_FROM_PTREE:
         unlinkMNodeFromPTree(args[1], args[2]);
         break;
+      case MetadataOperationType.SET_TTL:
+        setTTL(args[1], Long.parseLong(args[2]));
+        break;
       default:
         logger.error("Unrecognizable command {}", cmd);
     }
@@ -281,7 +285,7 @@ public class MManager {
    * <p> Add one timeseries to metadata.
    *
    * @param path the timeseries seriesPath
-   * @param dataType the datetype {@code DataType} for the timeseries
+   * @param dataType the dateType {@code DataType} for the timeseries
    * @param encoding the encoding function {@code Encoding} for the timeseries
    * @param compressor the compressor function {@code Compressor} for the time series
    * @return whether the measurement occurs for the first time in this storage group (if true, the
@@ -296,7 +300,7 @@ public class MManager {
           String.format("Timeseries %s already exist", path.getFullPath()));
     }
     IoTDBConfig conf = IoTDBDescriptor.getInstance().getConfig();
-    if (!checkFileNameByPath(path.getFullPath())) {
+    if (!checkStorageGroupByPath(path.getFullPath())) {
       if (!conf.isAutoCreateSchemaEnabled()) {
         throw new MetadataErrorException("Storage group should be created first");
       }
@@ -399,7 +403,7 @@ public class MManager {
    * this is just for compatibility  TEST ONLY
    *
    * @param path the timeseries seriesPath
-   * @param dataType the datetype {@code DataType} for the timeseries
+   * @param dataType the dateType {@code DataType} for the timeseries
    * @param encoding the encoding function {@code Encoding} for the timeseries
    */
   public void addPathToMTree(String path, String dataType, String encoding)
@@ -534,7 +538,7 @@ public class MManager {
     try {
       checkAndGetDataTypeCache.clear();
       mNodeCache.clear();
-      String dataFileName = mgraph.deletePath(path);
+      String storageGroupName = mgraph.deletePath(path);
       if (writeToLog) {
         BufferedWriter writer = getLogWriter();
         writer.write(MetadataOperationType.DELETE_PATH_FROM_MTREE + "," + path);
@@ -555,7 +559,7 @@ public class MManager {
       } else {
         maxSeriesNumberAmongStorageGroup--;
       }
-      return dataFileName;
+      return storageGroupName;
     } finally {
       lock.writeLock().unlock();
     }
@@ -593,13 +597,14 @@ public class MManager {
   /**
    * function for deleting storage groups of the given path from mTree.
    * the log format is like "delete_storage_group,sg1,sg2,sg3"
+   * TODO: return value unused
    */
   public boolean deleteStorageGroupsFromMTree(List<Path> deletePathList) throws MetadataErrorException {
     List<String> pathList = new ArrayList<>();
-    String jointPath = "";
+    StringBuilder jointPath = new StringBuilder();
     for (Path storagePath : deletePathList) {
       pathList.add(storagePath.getFullPath());
-      jointPath = jointPath + "," + storagePath.getFullPath();
+      jointPath.append(",").append(storagePath.getFullPath());
     }
     lock.writeLock().lock();
     try {
@@ -831,26 +836,11 @@ public class MManager {
   }
 
   /**
-   * Get the full storage group info.
-   *
-   * @return A HashSet instance which stores all storage group info
-   */
-  public Set<String> getAllStorageGroup() throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getAllStorageGroup();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
    * Get the full devices info.
    *
    * @return A HashSet instance which stores all devices info
    */
-  public Set<String> getAllDevices() throws PathErrorException, SQLException {
+  public Set<String> getAllDevices() throws SQLException {
 
     lock.readLock().lock();
     try {
@@ -965,6 +955,7 @@ public class MManager {
 
   /**
    * function for getting file name by path.
+   * TODO: return value unused
    */
   private String getStorageGroupNameByPath(MNode node, String path) throws StorageGroupException {
     lock.readLock().lock();
@@ -978,42 +969,55 @@ public class MManager {
   }
 
   /**
-   * function for checking file name by path.
+   * function for checking storage group name by path.
    */
-  boolean checkFileNameByPath(String path) {
+  boolean checkStorageGroupByPath(String path) {
 
     lock.readLock().lock();
     try {
-      return mgraph.checkFileNameByPath(path);
+      return mgraph.checkStorageGroupByPath(path);
     } finally {
       lock.readLock().unlock();
     }
   }
 
   /**
-   * function for getting all file names.
+   * Get the names of all storage groups.
+   *
+   * @return A list which stores all storage group names.
    */
-  public List<String> getAllStorageGroupNames() throws MetadataErrorException {
+  public List<String> getAllStorageGroupNames() {
 
     lock.readLock().lock();
     try {
-      Map<String, ArrayList<String>> res = getAllPathGroupByFileName(ROOT_NAME);
-      return new ArrayList<>(res.keySet());
+      return mgraph.getAllStorageGroupNames();
     } finally {
       lock.readLock().unlock();
     }
   }
 
   /**
-   * Get all file names for given seriesPath
+   * function for getting all storage groups' MNodes
+   */
+  public List<MNode> getAllStorageGroups() {
+    lock.readLock().lock();
+    try {
+      return mgraph.getAllStorageGroupNodes();
+    } finally {
+      lock.readLock().unlock();
+    }
+  }
+
+  /**
+   * Get all storage group names for given seriesPath
    *
-   * @return List of String represented all file names
+   * @return List of String represented all storage group names
    */
-  List<String> getAllFileNamesByPath(String path) throws MetadataErrorException {
+  List<String> getAllStorageGroupNamesByPath(String path) throws MetadataErrorException {
 
     lock.readLock().lock();
     try {
-      return mgraph.getAllFileNamesByPath(path);
+      return mgraph.getAllStorageGroupNamesByPath(path);
     } catch (PathErrorException e) {
       throw new MetadataErrorException(e);
     } finally {
@@ -1022,13 +1026,13 @@ public class MManager {
   }
 
   /**
-   * return a HashMap contains all the paths separated by File Name.
+   * return a HashMap contains all the paths separated by storage group name.
    */
-  Map<String, ArrayList<String>> getAllPathGroupByFileName(String path)
+  Map<String, List<String>> getAllPathGroupByStorageGroup(String path)
       throws MetadataErrorException {
     lock.readLock().lock();
     try {
-      return mgraph.getAllPathGroupByFilename(path);
+      return mgraph.getAllPathGroupByStorageGroup(path);
     } catch (PathErrorException e) {
       throw new MetadataErrorException(e);
     } finally {
@@ -1044,9 +1048,9 @@ public class MManager {
 
     lock.readLock().lock();
     try {
-      ArrayList<String> res = new ArrayList<>();
-      Map<String, ArrayList<String>> pathsGroupByFilename = getAllPathGroupByFileName(path);
-      for (ArrayList<String> ps : pathsGroupByFilename.values()) {
+      List<String> res = new ArrayList<>();
+      Map<String, List<String>> pathsGroupBySG = getAllPathGroupByStorageGroup(path);
+      for (List<String> ps : pathsGroupBySG.values()) {
         res.addAll(ps);
       }
       return res;
@@ -1156,7 +1160,7 @@ public class MManager {
   /**
    * function for getting node by path with check.
    */
-  MNode getNodeByPathWithCheck(String path) throws PathErrorException, StorageGroupException {
+  public MNode getNodeByPathWithCheck(String path) throws PathErrorException, StorageGroupException {
     lock.readLock().lock();
     try {
       return mgraph.getNodeByPathWithCheck(path);
@@ -1297,17 +1301,17 @@ public class MManager {
   /**
    * function for getting storage group name when creating schema automatically is enable
    */
-  public String getStorageGroupNameByAutoLevel(String fullPath, int level)
+  String getStorageGroupNameByAutoLevel(String fullPath, int level)
       throws PathErrorException {
     String[] nodeNames = fullPath.trim().split(DOUB_SEPARATOR);
-    String storageGroupName = nodeNames[0];
-    if (nodeNames.length < level || !storageGroupName.equals(ROOT_NAME)) {
+    StringBuilder storageGroupName = new StringBuilder(nodeNames[0]);
+    if (nodeNames.length < level || !storageGroupName.toString().equals(ROOT_NAME)) {
       throw new PathErrorException(String.format("Timeseries %s is not right.", fullPath));
     }
     for (int i = 1; i < level; i++) {
-      storageGroupName +=  IoTDBConstant.PATH_SEPARATOR + nodeNames[i];
+      storageGroupName.append(IoTDBConstant.PATH_SEPARATOR).append(nodeNames[i]);
     }
-    return storageGroupName;
+    return storageGroupName.toString();
   }
 
   /**
@@ -1378,4 +1382,23 @@ public class MManager {
       return dataType;
     }
   }
+
+  public void setTTL(String storageGroup, long dataTTL) throws PathErrorException, IOException {
+    lock.writeLock().lock();
+    try {
+      MNode sgNode = getNodeByPath(storageGroup);
+      if (!sgNode.isStorageGroup()) {
+        throw new NotStorageGroupException(storageGroup);
+      }
+      sgNode.setDataTTL(dataTTL);
+      if (writeToLog) {
+        BufferedWriter writer = getLogWriter();
+        writer.write(String.format("%s,%s,%s", MetadataOperationType.SET_TTL, storageGroup, dataTTL));
+        writer.newLine();
+        writer.flush();
+      }
+    } finally {
+      lock.writeLock().unlock();
+    }
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/MNode.java
index 3571cbd..86103bf 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MNode.java
@@ -22,6 +22,7 @@ import java.io.Serializable;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
@@ -52,6 +53,15 @@ public class MNode implements Serializable {
   private MNode parent;
   private Map<String, MNode> children;
 
+  private String fullPath;
+
+  /**
+   * when the data in a storage group is older than dataTTL, it is considered invalid and will
+   * be eventually removed.
+   * only set at storage group level.
+   */
+  private long dataTTL = Long.MAX_VALUE;
+
   /**
    * Constructor of MNode.
    */
@@ -208,4 +218,24 @@ public class MNode implements Serializable {
     this.name = name;
   }
 
+  public long getDataTTL() {
+    return dataTTL;
+  }
+
+  public void setDataTTL(long dataTTL) {
+    this.dataTTL = dataTTL;
+  }
+
+  public String getFullPath() {
+    if (fullPath != null) {
+      return fullPath;
+    }
+    StringBuilder builder = new StringBuilder(name);
+    MNode curr = this;
+    while (curr.parent != null) {
+      curr = curr.parent;
+      builder.insert(0, IoTDBConstant.PATH_SEPARATOR).insert(0, curr.name);
+    }
+    return fullPath = builder.toString();
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
index 50c2e51..7124455 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
@@ -23,12 +23,18 @@ import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.serializer.SerializerFeature;
 import java.io.Serializable;
 import java.sql.SQLException;
-import java.util.*;
-
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
-import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
@@ -40,7 +46,7 @@ import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 public class MTree implements Serializable {
 
   private static final long serialVersionUID = -4200394435237291964L;
-  private static final String DOUB_SEPARATOR = "\\.";
+  private static final String PATH_SEPARATOR = "\\.";
   private static final String NO_CHILD_ERROR = "Timeseries is not correct. Node[%s] "
       + "doesn't have child named:%s";
   private static final String NOT_LEAF_NODE = "Timeseries %s is not the leaf node";
@@ -52,28 +58,12 @@ public class MTree implements Serializable {
     this.root = new MNode(rootName, null, false);
   }
 
-  public MTree(MNode root) {
-    this.root = root;
-  }
-
-  /**
-   * this is just for compatibility
-   */
-  void addTimeseriesPath(String timeseriesPath, String dataType, String encoding)
-      throws PathErrorException {
-    TSDataType tsDataType = TSDataType.valueOf(dataType);
-    TSEncoding tsEncoding = TSEncoding.valueOf(encoding);
-    CompressionType compressionType = CompressionType.valueOf(TSFileDescriptor.getInstance().getConfig().getCompressor());
-    addTimeseriesPath(timeseriesPath, tsDataType, tsEncoding, compressionType,
-        Collections.emptyMap());
-  }
-
   /**
    * function for adding timeseries.It should check whether seriesPath exists.
    */
   void addTimeseriesPath(String timeseriesPath, TSDataType dataType, TSEncoding encoding,
       CompressionType compressor, Map<String, String> props) throws PathErrorException {
-    String[] nodeNames = timeseriesPath.trim().split(DOUB_SEPARATOR);
+    String[] nodeNames = timeseriesPath.trim().split(PATH_SEPARATOR);
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new PathErrorException(String.format("Timeseries %s is not right.", timeseriesPath));
     }
@@ -97,7 +87,7 @@ public class MTree implements Serializable {
    * function for adding deviceId
    */
   MNode addDeviceId(String deviceId) throws PathErrorException {
-    String[] nodeNames = deviceId.trim().split(DOUB_SEPARATOR);
+    String[] nodeNames = deviceId.trim().split(PATH_SEPARATOR);
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new PathErrorException(String.format("Timeseries %s is not right.", deviceId));
     }
@@ -146,7 +136,7 @@ public class MTree implements Serializable {
    * @param path -seriesPath not necessarily the whole seriesPath (possibly a prefix of a sequence)
    */
   boolean isPathExist(String path) {
-    String[] nodeNames = path.trim().split(DOUB_SEPARATOR);
+    String[] nodeNames = path.trim().split(PATH_SEPARATOR);
     MNode cur = root;
     int i = 0;
     while (i < nodeNames.length - 1) {
@@ -167,10 +157,10 @@ public class MTree implements Serializable {
   }
 
   /**
-   * function for checking whether the given path exists under the given mnode.
+   * function for checking whether the given path exists under the given mNode.
    */
   boolean isPathExist(MNode node, String path) {
-    String[] nodeNames = path.trim().split(DOUB_SEPARATOR);
+    String[] nodeNames = path.trim().split(PATH_SEPARATOR);
     if (nodeNames.length < 1) {
       return true;
     }
@@ -201,7 +191,7 @@ public class MTree implements Serializable {
    * make sure check seriesPath before setting storage group.
    */
   public void setStorageGroup(String path) throws StorageGroupException {
-    String[] nodeNames = path.split(DOUB_SEPARATOR);
+    String[] nodeNames = path.split(PATH_SEPARATOR);
     MNode cur = root;
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new StorageGroupException(
@@ -231,12 +221,14 @@ public class MTree implements Serializable {
               path));
     }
     cur = cur.getChild(nodeNames[i]);
+    cur.setDataTTL(IoTDBDescriptor.getInstance().getConfig().getDefaultTTL());
     cur.setStorageGroup(true);
-    setDataFileName(path, cur);
+
+    setStorageGroup(path, cur);
   }
 
-  public void deleteStorageGroup(String path) throws PathErrorException {
-    MNode cur = getNodeByPath(path);
+  void deleteStorageGroup(String path) throws PathErrorException {
+    MNode cur = getNode(path);
     if (!cur.isStorageGroup()) {
       throw new PathErrorException(String.format("The path %s is not a deletable storage group", path));
     }
@@ -255,7 +247,7 @@ public class MTree implements Serializable {
    * @apiNote :for cluster
    */
   boolean checkStorageGroup(String path) {
-    String[] nodeNames = path.split(DOUB_SEPARATOR);
+    String[] nodeNames = path.split(PATH_SEPARATOR);
     MNode cur = root;
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       return false;
@@ -273,29 +265,13 @@ public class MTree implements Serializable {
     return temp != null && temp.isStorageGroup();
   }
 
-  /**
-   * Check whether set file seriesPath for this node or not. If not, throw an exception
-   */
-  private void checkStorageGroup(MNode node) throws StorageGroupException {
-    if (node.getDataFileName() != null) {
-      throw new StorageGroupException(
-          String.format("The storage group %s has been set", node.getDataFileName()));
-    }
-    if (node.getChildren() == null) {
-      return;
-    }
-    for (MNode child : node.getChildren().values()) {
-      checkStorageGroup(child);
-    }
-  }
-
-  private void setDataFileName(String path, MNode node) {
+  private void setStorageGroup(String path, MNode node) {
     node.setDataFileName(path);
     if (node.getChildren() == null) {
       return;
     }
     for (MNode child : node.getChildren().values()) {
-      setDataFileName(path, child);
+      setStorageGroup(path, child);
     }
   }
 
@@ -306,7 +282,7 @@ public class MTree implements Serializable {
    * node.
    */
   String deletePath(String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException("Timeseries %s is not correct." + path);
     }
@@ -341,35 +317,6 @@ public class MTree implements Serializable {
   }
 
   /**
-   * Check whether the seriesPath given exists.
-   */
-  public boolean hasPath(String path) {
-    String[] nodes = path.split(DOUB_SEPARATOR);
-    if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
-      return false;
-    }
-    return hasPath(getRoot(), nodes, 1);
-  }
-
-  private boolean hasPath(MNode node, String[] nodes, int idx) {
-    if (idx >= nodes.length) {
-      return true;
-    }
-    if (("*").equals(nodes[idx])) {
-      boolean res = false;
-      for (MNode child : node.getChildren().values()) {
-        res |= hasPath(child, nodes, idx + 1);
-      }
-      return res;
-    } else {
-      if (node.hasChild(nodes[idx])) {
-        return hasPath(node.getChild(nodes[idx]), nodes, idx + 1);
-      }
-      return false;
-    }
-  }
-
-  /**
    * Get ColumnSchema for given seriesPath. Notice: Path must be a complete Path from root to leaf
    * node.
    */
@@ -395,8 +342,8 @@ public class MTree implements Serializable {
   }
 
   private MNode getLeafByPath(String path) throws PathErrorException {
-    checkPath(path);
-    String[] node = path.split(DOUB_SEPARATOR);
+    getNode(path);
+    String[] node = path.split(PATH_SEPARATOR);
     MNode cur = getRoot();
     for (int i = 1; i < node.length; i++) {
       cur = cur.getChild(node[i]);
@@ -409,7 +356,7 @@ public class MTree implements Serializable {
 
   private MNode getLeafByPath(MNode node, String path) throws PathErrorException {
     checkPath(node, path);
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = node.getChild(nodes[0]);
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
@@ -421,7 +368,7 @@ public class MTree implements Serializable {
   }
 
   private MNode getLeafByPathWithCheck(MNode node, String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length < 1 || !node.hasChild(nodes[0])) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -441,7 +388,7 @@ public class MTree implements Serializable {
   }
 
   private MNode getLeafByPathWithCheck(String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -461,24 +408,11 @@ public class MTree implements Serializable {
   }
 
   /**
-   * function for getting node by path.
-   */
-  MNode getNodeByPath(String path) throws PathErrorException {
-    checkPath(path);
-    String[] node = path.split(DOUB_SEPARATOR);
-    MNode cur = getRoot();
-    for (int i = 1; i < node.length; i++) {
-      cur = cur.getChild(node[i]);
-    }
-    return cur;
-  }
-
-  /**
    * function for getting node by path with file level check.
    */
-  MNode getNodeByPathWithFileLevelCheck(String path) throws PathErrorException, StorageGroupException {
-    boolean fileLevelChecked = false;
-    String[] nodes = path.split(DOUB_SEPARATOR);
+  MNode getNodeByPathWithStorageGroupCheck(String path) throws PathErrorException, StorageGroupException {
+    boolean storageGroupChecked = false;
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -486,44 +420,31 @@ public class MTree implements Serializable {
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       if (!cur.hasChild(nodes[i])) {
-        if (!fileLevelChecked) {
+        if (!storageGroupChecked) {
           throw new StorageGroupException("Storage group is not set for current seriesPath:" + path);
         }
         throw new PathErrorException(String.format(NO_CHILD_ERROR, cur.getName(), nodes[i]));
       }
       cur = cur.getChild(nodes[i]);
+
       if (cur.isStorageGroup()) {
-        fileLevelChecked = true;
+        storageGroupChecked = true;
       }
     }
-    if (!fileLevelChecked) {
+
+    if (!storageGroupChecked) {
       throw new StorageGroupException("Storage group is not set for current seriesPath:" + path);
     }
     return cur;
   }
 
   /**
-   * Extract the deviceType from given seriesPath.
+   * find and return a seriesPath specified by the path
    *
-   * @return String represents the deviceId
+   * @return last node in given seriesPath
    */
-  String getDeviceTypeByPath(String path) throws PathErrorException {
-    checkPath(path);
-    String[] nodes = path.split(DOUB_SEPARATOR);
-    if (nodes.length < 2) {
-      throw new PathErrorException(
-          String.format("Timeseries %s must have two or more nodes", path));
-    }
-    return nodes[0] + "." + nodes[1];
-  }
-
-  /**
-   * Check whether a seriesPath is available.
-   *
-   * @return last node in given seriesPath if current seriesPath is available
-   */
-  private MNode checkPath(String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+  MNode getNode(String path) throws PathErrorException {
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -538,7 +459,7 @@ public class MTree implements Serializable {
   }
 
   private void checkPath(MNode node, String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length < 1) {
       return;
     }
@@ -559,7 +480,7 @@ public class MTree implements Serializable {
    */
   String getStorageGroupNameByPath(String path) throws StorageGroupException {
 
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       if (cur == null) {
@@ -584,7 +505,7 @@ public class MTree implements Serializable {
    */
   List<String> getAllFileNamesByPath(String pathReg) throws PathErrorException {
     ArrayList<String> fileNames = new ArrayList<>();
-    String[] nodes = pathReg.split(DOUB_SEPARATOR);
+    String[] nodes = pathReg.split(PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
     }
@@ -625,7 +546,7 @@ public class MTree implements Serializable {
    */
   String getStorageGroupNameByPath(MNode node, String path) throws StorageGroupException {
 
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = node.getChild(nodes[0]);
     for (int i = 1; i < nodes.length; i++) {
       if (cur == null) {
@@ -650,7 +571,7 @@ public class MTree implements Serializable {
    */
   boolean checkFileNameByPath(String path) {
 
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = getRoot();
     for (int i = 1; i <= nodes.length; i++) {
       if (cur == null) {
@@ -670,9 +591,9 @@ public class MTree implements Serializable {
    *
    * @return A HashMap whose Keys are separated by the storage file name.
    */
-  HashMap<String, ArrayList<String>> getAllPath(String pathReg) throws PathErrorException {
-    HashMap<String, ArrayList<String>> paths = new HashMap<>();
-    String[] nodes = pathReg.split(DOUB_SEPARATOR);
+  HashMap<String, List<String>> getAllPath(String pathReg) throws PathErrorException {
+    HashMap<String, List<String>> paths = new HashMap<>();
+    String[] nodes = pathReg.split(PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
     }
@@ -681,11 +602,31 @@ public class MTree implements Serializable {
   }
 
   /**
+   *
+   * @return all storage groups' MNodes
+   * @throws PathErrorException
+   */
+  List<MNode> getAllStorageGroupNodes() {
+    List<MNode> ret = new ArrayList<>();
+    Stack<MNode> nodeStack = new Stack<>();
+    nodeStack.add(getRoot());
+    while (!nodeStack.isEmpty()) {
+      MNode current = nodeStack.pop();
+      if (current.isStorageGroup()) {
+        ret.add(current);
+      } else if (current.hasChildren()){
+        nodeStack.addAll(current.getChildren().values());
+      }
+    }
+    return ret;
+  }
+
+  /**
    * function for getting all timeseries paths under the given seriesPath.
    */
   List<List<String>> getShowTimeseriesPath(String pathReg) throws PathErrorException {
     List<List<String>> res = new ArrayList<>();
-    String[] nodes = pathReg.split(DOUB_SEPARATOR);
+    String[] nodes = pathReg.split(PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
     }
@@ -700,7 +641,7 @@ public class MTree implements Serializable {
    */
   List<String> getLeafNodePathInNextLevel(String path) throws PathErrorException {
     List<String> ret = new ArrayList<>();
-    MNode cur = checkPath(path);
+    MNode cur = getNode(path);
     for (MNode child : cur.getChildren().values()) {
       if (child.isLeaf()) {
         ret.add(path + "." + child.getName());
@@ -712,10 +653,10 @@ public class MTree implements Serializable {
   /**
    * function for getting all paths in list.
    */
-  ArrayList<String> getAllPathInList(String path) throws PathErrorException {
-    ArrayList<String> res = new ArrayList<>();
-    HashMap<String, ArrayList<String>> mapRet = getAllPath(path);
-    for (ArrayList<String> value : mapRet.values()) {
+  List<String> getAllPathInList(String path) throws PathErrorException {
+    List<String> res = new ArrayList<>();
+    HashMap<String, List<String>> mapRet = getAllPath(path);
+    for (List<String> value : mapRet.values()) {
       res.addAll(value);
     }
     return res;
@@ -727,7 +668,7 @@ public class MTree implements Serializable {
    * @return The total count of storage-level nodes.
    */
   int getFileCountForOneType(String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length != 2 || !nodes[0].equals(getRoot().getName()) || !getRoot()
         .hasChild(nodes[1])) {
       throw new PathErrorException(
@@ -769,8 +710,8 @@ public class MTree implements Serializable {
    *
    * @return a list contains all distinct storage groups
    */
-  Set<String> getAllStorageGroup() {
-    HashSet<String> res = new HashSet<>();
+  List<String> getAllStorageGroupList() {
+    List<String> res = new ArrayList<>();
     MNode rootNode;
     if ((rootNode = getRoot()) != null) {
       findStorageGroup(rootNode, "root", res);
@@ -778,7 +719,7 @@ public class MTree implements Serializable {
     return res;
   }
 
-  private void findStorageGroup(MNode node, String path, HashSet<String> res) {
+  private void findStorageGroup(MNode node, String path, List<String> res) {
     if (node.isStorageGroup()) {
       res.add(path);
       return;
@@ -868,7 +809,7 @@ public class MTree implements Serializable {
    */
   ArrayList<String> getDeviceForOneType(String type) throws PathErrorException {
     String path = getRoot().getName() + "." + type;
-    checkPath(path);
+    getNode(path);
     HashMap<String, Integer> deviceMap = new HashMap<>();
     MNode typeNode = getRoot().getChild(type);
     putDeviceToMap(getRoot().getName(), typeNode, deviceMap);
@@ -893,7 +834,7 @@ public class MTree implements Serializable {
    * @return a list contains all column schema
    */
   ArrayList<MeasurementSchema> getSchemaForOneType(String path) throws PathErrorException {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     if (nodes.length != 2 || !nodes[0].equals(getRoot().getName()) || !getRoot()
         .hasChild(nodes[1])) {
       throw new PathErrorException(
@@ -912,7 +853,7 @@ public class MTree implements Serializable {
    */
   ArrayList<MeasurementSchema> getSchemaForOneStorageGroup(String path) {
 
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     HashMap<String, MeasurementSchema> leafMap = new HashMap<>();
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
@@ -927,7 +868,7 @@ public class MTree implements Serializable {
    * function for getting schema map for one storage group.
    */
   Map<String, MeasurementSchema> getSchemaMapForOneStorageGroup(String path) {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
@@ -939,7 +880,7 @@ public class MTree implements Serializable {
    * function for getting num schema map for one file node.
    */
   Map<String, Integer> getNumSchemaMapForOneFileNode(String path) {
-    String[] nodes = path.split(DOUB_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR);
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
@@ -960,7 +901,7 @@ public class MTree implements Serializable {
   }
 
   private void findPath(MNode node, String[] nodes, int idx, String parent,
-      HashMap<String, ArrayList<String>> paths) {
+      HashMap<String, List<String>> paths) {
     if (node.isLeaf()) {
       if (nodes.length <= idx) {
         String fileName = node.getDataFileName();
@@ -1023,12 +964,12 @@ public class MTree implements Serializable {
     }
   }
 
-  private void putAPath(HashMap<String, ArrayList<String>> paths, String fileName,
+  private void putAPath(HashMap<String, List<String>> paths, String fileName,
       String nodePath) {
     if (paths.containsKey(fileName)) {
       paths.get(fileName).add(nodePath);
     } else {
-      ArrayList<String> pathList = new ArrayList<>();
+      List<String> pathList = new ArrayList<>();
       pathList.add(nodePath);
       paths.put(fileName, pathList);
     }
@@ -1045,15 +986,15 @@ public class MTree implements Serializable {
 
   private JSONObject toJson() {
     JSONObject jsonObject = new JSONObject();
-    jsonObject.put(getRoot().getName(), mnodeToJSON(getRoot()));
+    jsonObject.put(getRoot().getName(), mNodeToJSON(getRoot()));
     return jsonObject;
   }
 
-  private JSONObject mnodeToJSON(MNode node) {
+  private JSONObject mNodeToJSON(MNode node) {
     JSONObject jsonObject = new JSONObject();
     if (!node.isLeaf() && node.getChildren().size() > 0) {
       for (MNode child : node.getChildren().values()) {
-        jsonObject.put(child.getName(), mnodeToJSON(child));
+        jsonObject.put(child.getName(), mNodeToJSON(child));
       }
     } else if (node.isLeaf()) {
       jsonObject.put("DataType", node.getSchema().getType());
@@ -1072,10 +1013,10 @@ public class MTree implements Serializable {
   /**
    * combine multiple metadata in string format
    */
-  static String combineMetadataInStrings(String[] metadatas) {
-    JSONObject[] jsonObjects = new JSONObject[metadatas.length];
+  static String combineMetadataInStrings(String[] metadataStrs) {
+    JSONObject[] jsonObjects = new JSONObject[metadataStrs.length];
     for (int i = 0; i < jsonObjects.length; i++) {
-      jsonObjects[i] = JSONObject.parseObject(metadatas[i]);
+      jsonObjects[i] = JSONObject.parseObject(metadataStrs[i]);
     }
 
     JSONObject root = jsonObjects[0];
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
index 72010ac..dce3523 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
@@ -34,5 +34,6 @@ public class MetadataOperationType {
   public static final String UNLINK_MNODE_FROM_PTREE = "7";
   public static final String ADD_INDEX_TO_PATH = "8";
   public static final String DELETE_INDEX_FROM_PATH = "9";
-  public static final String DELETE_STORAGE_GROUP_FROM_MTREE = "10";
+  public static final String SET_TTL = "10";
+  public static final String DELETE_STORAGE_GROUP_FROM_MTREE = "11";
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
index d62bb7b..32086ee 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
@@ -36,25 +36,19 @@ public class PTree implements Serializable {
   private String name;
   private String space = "    ";
 
-  public PTree(String name, MTree mTree) {
+  PTree(String name, MTree mTree) {
     this.setRoot(new PNode(name, null, false));
     this.setName(name);
     this.setmTree(mTree);
   }
 
-  public PTree(String name, PNode root, MTree mTree) {
-    this.setName(name);
-    this.setRoot(root);
-    this.setmTree(mTree);
-  }
-
   /**
    * Add a seriesPath to current PTree
    *
-   * @return The count of new added {@code PNode}
+   * @return The count of new added {@code PNode} TODO: unused
    * @throws PathErrorException
    */
-  public int addPath(String path) throws PathErrorException {
+  int addPath(String path) throws PathErrorException {
     int addCount = 0;
     if (getRoot() == null) {
       throw new PathErrorException("Root Node is null, Please initialize root first");
@@ -88,7 +82,7 @@ public class PTree implements Serializable {
    *
    * @throws PathErrorException
    */
-  public void deletePath(String path) throws PathErrorException {
+  void deletePath(String path) throws PathErrorException {
     String[] nodes = path.split("\\.");
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException("Path not correct. Path:" + path);
@@ -109,7 +103,7 @@ public class PTree implements Serializable {
    *
    * @throws PathErrorException
    */
-  public void linkMNode(String pTreePath, String mTreePath) throws PathErrorException {
+  void linkMNode(String pTreePath, String mTreePath) throws PathErrorException {
     List<String> paths = mTree.getAllPathInList(mTreePath);
     String[] nodes = pTreePath.trim().split("\\.");
     PNode leaf = getLeaf(getRoot(), nodes, 0);
@@ -123,7 +117,7 @@ public class PTree implements Serializable {
    *
    * @throws PathErrorException
    */
-  public void unlinkMNode(String pTreePath, String mTreePath) throws PathErrorException {
+  void unlinkMNode(String pTreePath, String mTreePath) throws PathErrorException {
     List<String> paths = mTree.getAllPathInList(mTreePath);
     String[] nodes = pTreePath.trim().split("\\.");
     PNode leaf = getLeaf(getRoot(), nodes, 0);
@@ -157,24 +151,24 @@ public class PTree implements Serializable {
    * @return Paths will be separated by the {@code MNode.dataFileName} in the HashMap
    * @throws PathErrorException
    */
-  public HashMap<String, ArrayList<String>> getAllLinkedPath(String path)
+  HashMap<String, List<String>> getAllLinkedPath(String path)
       throws PathErrorException {
     String[] nodes = path.trim().split("\\.");
     PNode leaf = getLeaf(getRoot(), nodes, 0);
-    HashMap<String, ArrayList<String>> res = new HashMap<>();
+    HashMap<String, List<String>> res = new HashMap<>();
 
     for (String MPath : leaf.getLinkedMTreePathMap().keySet()) {
-      HashMap<String, ArrayList<String>> tr = getmTree().getAllPath(MPath);
+      HashMap<String, List<String>> tr = getmTree().getAllPath(MPath);
       mergePathRes(res, tr);
     }
     return res;
   }
 
-  private void mergePathRes(HashMap<String, ArrayList<String>> res,
-      HashMap<String, ArrayList<String>> tr) {
+  private void mergePathRes(HashMap<String, List<String>> res,
+      HashMap<String, List<String>> tr) {
     for (String key : tr.keySet()) {
       if (!res.containsKey(key)) {
-        res.put(key, new ArrayList<String>());
+        res.put(key, new ArrayList<>());
       }
       for (String p : tr.get(key)) {
         if (!res.get(key).contains(p)) {
@@ -190,41 +184,41 @@ public class PTree implements Serializable {
   }
 
   private String pNodeToString(PNode node, int tab) {
-    String s = "";
+    StringBuilder s = new StringBuilder();
     for (int i = 0; i < tab; i++) {
-      s += space;
+      s.append(space);
     }
-    s += node.getName();
+    s.append(node.getName());
     if (!node.isLeaf() && node.getChildren().size() > 0) {
-      s += ":{\n";
+      s.append(":{\n");
       int first = 0;
       for (PNode child : node.getChildren().values()) {
         if (first == 0) {
           first = 1;
         } else {
-          s += ",\n";
+          s.append(",\n");
         }
-        s += pNodeToString(child, tab + 1);
+        s.append(pNodeToString(child, tab + 1));
       }
-      s += "\n";
+      s.append("\n");
       for (int i = 0; i < tab; i++) {
-        s += space;
+        s.append(space);
       }
-      s += "}";
+      s.append("}");
     } else if (node.isLeaf()) {
-      s += ":{\n";
-      String[] linkedPaths = new String[node.getLinkedMTreePathMap().values().size()];
-      linkedPaths = node.getLinkedMTreePathMap().values().toArray(linkedPaths);
+      s.append(":{\n");
+      String[] linkedPaths = node.getLinkedMTreePathMap().values().stream().map(
+          Object::toString).toArray(String[]::new);
       for (int i = 0; i < linkedPaths.length; i++) {
         if (i != linkedPaths.length - 1) {
-          s += getTabs(tab + 1) + linkedPaths[i] + ",\n";
+          s.append(getTabs(tab + 1)).append(linkedPaths[i]).append(",\n");
         } else {
-          s += getTabs(tab + 1) + linkedPaths[i] + "\n";
+          s.append(getTabs(tab + 1)).append(linkedPaths[i]).append("\n");
         }
       }
-      s += getTabs(tab) + "}";
+      s.append(getTabs(tab)).append("}");
     }
-    return s;
+    return s.toString();
   }
 
   private String getTabs(int count) {
@@ -243,11 +237,11 @@ public class PTree implements Serializable {
     this.name = name;
   }
 
-  public MTree getmTree() {
+  private MTree getmTree() {
     return mTree;
   }
 
-  public void setmTree(MTree mTree) {
+  private void setmTree(MTree mTree) {
     this.mTree = mTree;
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/monitor/StatMonitor.java b/server/src/main/java/org/apache/iotdb/db/monitor/StatMonitor.java
index 440c1ad..1078a1c 100644
--- a/server/src/main/java/org/apache/iotdb/db/monitor/StatMonitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/monitor/StatMonitor.java
@@ -31,6 +31,7 @@ import org.apache.iotdb.db.concurrent.ThreadName;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.StorageEngine;
+import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
@@ -388,7 +389,7 @@ public class StatMonitor implements IService {
           numInsert.incrementAndGet();
           pointNum = entry.getValue().dataPointList.size();
           numPointsInsert.addAndGet(pointNum);
-        } catch (StorageEngineException e) {
+        } catch (ProcessorException e) {
           numInsertError.incrementAndGet();
           logger.error("Inserting stat points error.", e);
         }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java b/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
index 4971b06..01eed3f 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
@@ -142,6 +142,7 @@ public class QueryProcessor {
       case INDEXQUERY:
       case GRANT_WATERMARK_EMBEDDING:
       case REVOKE_WATERMARK_EMBEDDING:
+      case TTL:
         return operator;
       case QUERY:
       case UPDATE:
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
index 8cd2338..8479e7a 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
@@ -93,10 +93,16 @@ public class SQLConstant {
   public static final int TOK_PROPERTY_LINK = 57;
   public static final int TOK_PROPERTY_UNLINK = 58;
   public static final int TOK_LIST = 59;
+
+
   public static final int TOK_DURATION = 60;
   public static final int TOK_DATE_EXPR = 61;
   public static final int TOK_METADATA_DELETE_FILE_LEVEL = 62;
 
+  public static final int TOK_SET = 63;
+  public static final int TOK_UNSET = 64;
+  public static final int TOK_SHOW = 65;
+
   public static final Map<Integer, String> tokenSymbol = new HashMap<>();
   public static final Map<Integer, String> tokenNames = new HashMap<>();
   public static final Map<Integer, Integer> reverseWords = new HashMap<>();
@@ -152,6 +158,9 @@ public class SQLConstant {
     tokenNames.put(TOK_PROPERTY_UNLINK, "TOK_PROPERTY_UNLINK");
 
     tokenNames.put(TOK_LIST, "TOK_LIST");
+    tokenNames.put(TOK_SET, "TOK_SET");
+    tokenNames.put(TOK_UNSET, "TOK_UNSET");
+    tokenNames.put(TOK_SHOW, "TOK_SHOW");
   }
 
   static {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/AbstractQueryProcessExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/AbstractQueryProcessExecutor.java
index 9cd483c..4b63d04 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/AbstractQueryProcessExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/AbstractQueryProcessExecutor.java
@@ -18,6 +18,9 @@
  */
 package org.apache.iotdb.db.qp.executor;
 
+import static org.apache.iotdb.db.conf.IoTDBConstant.STORAGE_GROUP;
+import static org.apache.iotdb.db.conf.IoTDBConstant.TTL;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -28,6 +31,7 @@ import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.metadata.MManager;
+import org.apache.iotdb.db.metadata.MNode;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.AggregationPlan;
 import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
@@ -35,18 +39,24 @@ import org.apache.iotdb.db.qp.physical.crud.FillQueryPlan;
 import org.apache.iotdb.db.qp.physical.crud.GroupByPlan;
 import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
 import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
+import org.apache.iotdb.db.query.dataset.ListDataSet;
 import org.apache.iotdb.db.query.dataset.DeviceIterateDataSet;
 import org.apache.iotdb.db.query.executor.EngineQueryRouter;
 import org.apache.iotdb.db.query.executor.IEngineQueryRouter;
 import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.Field;
 import org.apache.iotdb.tsfile.read.common.Path;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.read.expression.QueryExpression;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.utils.Binary;
 
 public abstract class AbstractQueryProcessExecutor implements IQueryProcessExecutor {
 
-  protected IEngineQueryRouter queryRouter = new EngineQueryRouter();
+  IEngineQueryRouter queryRouter = new EngineQueryRouter();
 
   @Override
   public QueryDataSet processQuery(PhysicalPlan queryPlan, QueryContext context)
@@ -57,11 +67,50 @@ public abstract class AbstractQueryProcessExecutor implements IQueryProcessExecu
       return processDataQuery((QueryPlan) queryPlan, context);
     } else if (queryPlan instanceof AuthorPlan) {
       return processAuthorQuery((AuthorPlan) queryPlan, context);
+    } else if(queryPlan instanceof ShowTTLPlan) {
+      return processShowTTLQuery((ShowTTLPlan) queryPlan);
     } else {
       throw new ProcessorException(String.format("Unrecognized query plan %s", queryPlan));
     }
   }
 
+  private QueryDataSet processShowTTLQuery(ShowTTLPlan showTTLPlan) {
+    List<Path> paths = new ArrayList<>();
+    paths.add(new Path(STORAGE_GROUP));
+    paths.add(new Path(TTL));
+    List<TSDataType> dataTypes = new ArrayList<>();
+    dataTypes.add(TSDataType.TEXT);
+    dataTypes.add(TSDataType.INT64);
+    ListDataSet listDataSet = new ListDataSet(paths, dataTypes);
+
+    List<String> selectedSgs = showTTLPlan.getStorageGroups();
+
+    List<MNode> storageGroups = MManager.getInstance().getAllStorageGroups();
+    int i = 0;
+    for (MNode mNode : storageGroups) {
+      String sgName = mNode.getFullPath();
+      if (!selectedSgs.isEmpty() && !selectedSgs.contains(sgName)) {
+        continue;
+      }
+      RowRecord rowRecord = new RowRecord(i++);
+      Field sg = new Field(TSDataType.TEXT);
+      Field ttl;
+      sg.setBinaryV(new Binary(sgName));
+      if (mNode.getDataTTL() != Long.MAX_VALUE) {
+        ttl = new Field(TSDataType.INT64);
+        ttl.setLongV(mNode.getDataTTL());
+      } else {
+        ttl = new Field(null);
+        ttl.setNull();
+      }
+      rowRecord.addField(sg);
+      rowRecord.addField(ttl);
+      listDataSet.putRecord(rowRecord);
+    }
+
+    return listDataSet;
+  }
+
   protected abstract QueryDataSet processAuthorQuery(AuthorPlan plan, QueryContext context)
       throws ProcessorException;
 
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/QueryProcessExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/QueryProcessExecutor.java
index 7b9db32..7816f8f 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/QueryProcessExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/QueryProcessExecutor.java
@@ -60,9 +60,10 @@ import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
 import org.apache.iotdb.db.qp.physical.sys.PropertyPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
-import org.apache.iotdb.db.query.dataset.AuthDataSet;
+import org.apache.iotdb.db.query.dataset.ListDataSet;
 import org.apache.iotdb.db.query.fill.IFill;
 import org.apache.iotdb.db.utils.AuthUtils;
 import org.apache.iotdb.db.utils.TypeInferenceUtils;
@@ -131,9 +132,21 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
       case PROPERTY:
         PropertyPlan property = (PropertyPlan) plan;
         return operateProperty(property);
+      case TTL:
+        operateTTL((SetTTLPlan) plan);
+        return true;
       default:
         throw new UnsupportedOperationException(
-            String.format("operation %s does not support", plan.getOperatorType()));
+            String.format("operation %s is not supported", plan.getOperatorType()));
+    }
+  }
+
+  private void operateTTL(SetTTLPlan plan) throws ProcessorException {
+    try {
+      MManager.getInstance().setTTL(plan.getStorageGroup(), plan.getDataTTL());
+      StorageEngine.getInstance().setTTL(plan.getStorageGroup(), plan.getDataTTL());
+    } catch (PathErrorException | IOException | StorageEngineException e) {
+      throw new ProcessorException(e);
     }
   }
 
@@ -250,7 +263,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
       return storageEngine.insert(insertPlan);
 
     } catch (PathErrorException | StorageEngineException | MetadataErrorException | CacheException e) {
-      throw new ProcessorException(e.getMessage());
+      throw new ProcessorException(e);
     }
   }
 
@@ -259,6 +272,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     try {
       String[] measurementList = batchInsertPlan.getMeasurements();
       String deviceId = batchInsertPlan.getDeviceId();
+
       MNode node = mManager.getNodeByDeviceIdFromCache(deviceId);
       Object[] values;
       IoTDBConfig conf = IoTDBDescriptor.getInstance().getConfig();
@@ -507,7 +521,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
       throw new ProcessorException(e);
     }
 
-    AuthDataSet dataSet;
+    ListDataSet dataSet;
 
     try {
       switch (authorType) {
@@ -538,13 +552,13 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     return dataSet;
   }
 
-  private AuthDataSet executeListRole(IAuthorizer authorizer) {
+  private ListDataSet executeListRole(IAuthorizer authorizer) {
     int index = 0;
     List<Path> headerList = new ArrayList<>();
     List<TSDataType> typeList = new ArrayList<>();
     headerList.add(new Path(ROLE));
     typeList.add(TSDataType.TEXT);
-    AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+    ListDataSet dataSet = new ListDataSet(headerList, typeList);
     List<String> roleList = authorizer.listAllRoles();
     for (String role : roleList) {
       RowRecord record = new RowRecord(index++);
@@ -556,14 +570,14 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     return dataSet;
   }
 
-  private AuthDataSet executeListUser(IAuthorizer authorizer) {
+  private ListDataSet executeListUser(IAuthorizer authorizer) {
     List<String> userList = authorizer.listAllUsers();
     List<Path> headerList = new ArrayList<>();
     List<TSDataType> typeList = new ArrayList<>();
     headerList.add(new Path(USER));
     typeList.add(TSDataType.TEXT);
     int index = 0;
-    AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+    ListDataSet dataSet = new ListDataSet(headerList, typeList);
     for (String user : userList) {
       RowRecord record = new RowRecord(index++);
       Field field = new Field(TSDataType.TEXT);
@@ -574,7 +588,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     return dataSet;
   }
 
-  private AuthDataSet executeListRoleUsers(IAuthorizer authorizer, String roleName)
+  private ListDataSet executeListRoleUsers(IAuthorizer authorizer, String roleName)
       throws AuthException {
     Role role = authorizer.getRole(roleName);
     if (role == null) {
@@ -584,7 +598,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     List<TSDataType> typeList = new ArrayList<>();
     headerList.add(new Path(USER));
     typeList.add(TSDataType.TEXT);
-    AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+    ListDataSet dataSet = new ListDataSet(headerList, typeList);
     List<String> userList = authorizer.listAllUsers();
     int index = 0;
     for (String userN : userList) {
@@ -600,7 +614,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     return dataSet;
   }
 
-  private AuthDataSet executeListUserRoles(IAuthorizer authorizer, String userName)
+  private ListDataSet executeListUserRoles(IAuthorizer authorizer, String userName)
       throws AuthException {
     User user = authorizer.getUser(userName);
     if (user != null) {
@@ -608,7 +622,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
       List<TSDataType> typeList = new ArrayList<>();
       headerList.add(new Path(ROLE));
       typeList.add(TSDataType.TEXT);
-      AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+      ListDataSet dataSet = new ListDataSet(headerList, typeList);
       int index = 0;
       for (String roleN : user.getRoleList()) {
         RowRecord record = new RowRecord(index++);
@@ -623,7 +637,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     }
   }
 
-  private AuthDataSet executeListRolePrivileges(IAuthorizer authorizer, String roleName, Path path)
+  private ListDataSet executeListRolePrivileges(IAuthorizer authorizer, String roleName, Path path)
       throws AuthException {
     Role role = authorizer.getRole(roleName);
     if (role != null) {
@@ -631,7 +645,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
       List<TSDataType> typeList = new ArrayList<>();
       headerList.add(new Path(PRIVILEGE));
       typeList.add(TSDataType.TEXT);
-      AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+      ListDataSet dataSet = new ListDataSet(headerList, typeList);
       int index = 0;
       for (PathPrivilege pathPrivilege : role.getPrivilegeList()) {
         if (path == null || AuthUtils
@@ -649,7 +663,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     }
   }
 
-  private AuthDataSet executeListUserPrivileges(IAuthorizer authorizer, String userName, Path path)
+  private ListDataSet executeListUserPrivileges(IAuthorizer authorizer, String userName, Path path)
       throws AuthException {
     User user = authorizer.getUser(userName);
     if (user == null) {
@@ -661,7 +675,7 @@ public class QueryProcessExecutor extends AbstractQueryProcessExecutor {
     headerList.add(new Path(PRIVILEGE));
     typeList.add(TSDataType.TEXT);
     typeList.add(TSDataType.TEXT);
-    AuthDataSet dataSet = new AuthDataSet(headerList, typeList);
+    ListDataSet dataSet = new ListDataSet(headerList, typeList);
     int index = 0;
     for (PathPrivilege pathPrivilege : user.getPrivilegeList()) {
       if (path == null || AuthUtils.pathBelongsTo(path.getFullPath(), pathPrivilege.getPath())) {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
index a6cb607..8b889a8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
@@ -73,6 +73,7 @@ public abstract class Operator {
     GRANT_USER_PRIVILEGE, REVOKE_USER_PRIVILEGE, GRANT_USER_ROLE, REVOKE_USER_ROLE, CREATE_ROLE,
     DELETE_ROLE, GRANT_ROLE_PRIVILEGE, REVOKE_ROLE_PRIVILEGE, LIST_USER, LIST_ROLE,
     LIST_USER_PRIVILEGE, LIST_ROLE_PRIVILEGE, LIST_USER_ROLES, LIST_ROLE_USERS,
-    GRANT_WATERMARK_EMBEDDING, REVOKE_WATERMARK_EMBEDDING, DELETE_STORAGE_GROUP,
+    GRANT_WATERMARK_EMBEDDING, REVOKE_WATERMARK_EMBEDDING,
+    TTL, DELETE_STORAGE_GROUP
   }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/SetTTLOperator.java
similarity index 57%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/sys/SetTTLOperator.java
index dd27fc5..d842165 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/SetTTLOperator.java
@@ -15,22 +15,36 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.jdbc;
+package org.apache.iotdb.db.qp.logical.sys;
+
+import org.apache.iotdb.db.qp.logical.RootOperator;
+
+public class SetTTLOperator extends RootOperator {
 
-import java.sql.SQLException;
+  private String storageGroup;
+  private long dataTTL;
 
-public class IoTDBSQLException extends SQLException {
+  public SetTTLOperator(int tokenIntType) {
+    super(tokenIntType);
+    this.operatorType = OperatorType.TTL;
+  }
 
-  private static final long serialVersionUID = -3306001287342258977L;
+  public String getStorageGroup() {
+    return storageGroup;
+  }
 
-  public IoTDBSQLException(String reason) {
-    super(reason);
+  public void setStorageGroup(String storageGroup) {
+    this.storageGroup = storageGroup;
   }
 
-  public IoTDBSQLException(Throwable cause) {
-    super(cause);
+  public long getDataTTL() {
+    return dataTTL;
   }
 
-}
+  public void setDataTTL(long dataTTL) {
+    this.dataTTL = dataTTL;
+  }
+}
\ No newline at end of file
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/ShowTTLOperator.java
similarity index 62%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
copy to server/src/main/java/org/apache/iotdb/db/qp/logical/sys/ShowTTLOperator.java
index dd27fc5..b8406ef 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/ShowTTLOperator.java
@@ -15,22 +15,26 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.jdbc;
+package org.apache.iotdb.db.qp.logical.sys;
 
-import java.sql.SQLException;
+import java.util.List;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.qp.logical.RootOperator;
 
-public class IoTDBSQLException extends SQLException {
+public class ShowTTLOperator extends RootOperator {
 
-  private static final long serialVersionUID = -3306001287342258977L;
+  private List<String> storageGroups;
 
-  public IoTDBSQLException(String reason) {
-    super(reason);
+  public ShowTTLOperator(List<String> storageGroups) {
+    super(SQLConstant.TOK_SHOW);
+    this.operatorType = OperatorType.TTL;
+    this.storageGroups = storageGroups;
   }
 
-  public IoTDBSQLException(Throwable cause) {
-    super(cause);
+  public List<String> getStorageGroups() {
+    return storageGroups;
   }
-
-}
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTTLPlan.java
similarity index 51%
copy from server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java
copy to server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTTLPlan.java
index 87fa4d6..268d554 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTTLPlan.java
@@ -15,39 +15,51 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.db.query.dataset;
+package org.apache.iotdb.db.qp.physical.sys;
 
-import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.tsfile.read.common.Path;
-import org.apache.iotdb.tsfile.read.common.RowRecord;
-import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
-public class AuthDataSet extends QueryDataSet {
+public class SetTTLPlan extends PhysicalPlan {
 
-  private List<RowRecord> records = new ArrayList<>();
-  private int index = 0;
+  private String storageGroup;
+  private long dataTTL;
 
-  public AuthDataSet(List<Path> paths,
-      List<TSDataType> dataTypes) {
-    super(paths, dataTypes);
+  public SetTTLPlan(String storageGroup, long dataTTL) {
+    // set TTL
+    super(false, OperatorType.TTL);
+    this.storageGroup = storageGroup;
+    this.dataTTL = dataTTL;
   }
 
-  @Override
-  public boolean hasNext() throws IOException {
-    return index < records.size();
+  public SetTTLPlan(String storageGroup) {
+    // unset TTL
+    this(storageGroup, Long.MAX_VALUE);
   }
 
   @Override
-  public RowRecord next() {
-    return records.get(index++);
+  public List<Path> getPaths() {
+    return null;
+  }
+
+  public String getStorageGroup() {
+    return storageGroup;
+  }
+
+  public void setStorageGroup(String storageGroup) {
+    this.storageGroup = storageGroup;
+  }
+
+  public long getDataTTL() {
+    return dataTTL;
   }
 
-  public void putRecord(RowRecord newRecord) {
-    records.add(newRecord);
+  public void setDataTTL(long dataTTL) {
+    this.dataTTL = dataTTL;
   }
-}
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowTTLPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowTTLPlan.java
new file mode 100644
index 0000000..5061b4e
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ShowTTLPlan.java
@@ -0,0 +1,30 @@
+/*
+ * 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 ag [...]
+ */
+
+package org.apache.iotdb.db.qp.physical.sys;
+
+import java.util.List;
+import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.tsfile.read.common.Path;
+
+public class ShowTTLPlan extends PhysicalPlan {
+
+  private List<String> storageGroups;
+
+  public ShowTTLPlan(List<String> storageGroups) {
+    super(true);
+    this.storageGroups = storageGroups;
+    setOperatorType(OperatorType.TTL);
+  }
+
+  @Override
+  public List<Path> getPaths() {
+    return null;
+  }
+
+  public List<String> getStorageGroups() {
+    return storageGroups;
+  }
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index 9e900ad..b3c8ae6 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -20,6 +20,58 @@ package org.apache.iotdb.db.qp.strategy;
 
 import static org.apache.iotdb.db.qp.constant.SQLConstant.LESSTHAN;
 import static org.apache.iotdb.db.qp.constant.SQLConstant.LESSTHANOREQUALTO;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_AND;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_EQ;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_GT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_GTE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_LT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_LTE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_NEQ;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_NOT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.OPERATOR_OR;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_ADD;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_AGGREGATE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_ALL;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_ALTER;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_CREATE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_DATETIME;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_DELETE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_DROP;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_FILL;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_FROM;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_GRANT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_GRANT_WATERMARK_EMBEDDING;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_GROUPBY;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_GROUPBY_DEVICE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_INSERT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LABEL;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LIMIT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LINEAR;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LINK;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LIST;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_LOAD;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_PATH;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_PREVIOUS;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_PRIVILEGES;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_PROPERTY;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_QUERY;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_REVOKE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_REVOKE_WATERMARK_EMBEDDING;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_ROLE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_ROOT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_SELECT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_SET;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_SHOW;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_SLIMIT;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_SOFFSET;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_STORAGEGROUP;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_TIMESERIES;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_TTL;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_UNLINK;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_UNSET;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_UPDATE;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_USER;
+import static org.apache.iotdb.db.sql.parse.TqlParser.TOK_WHERE;
 
 import java.time.ZoneId;
 import java.util.ArrayList;
@@ -29,7 +81,6 @@ import java.util.List;
 import java.util.Map;
 import org.antlr.runtime.Token;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.exception.ArgsErrorException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.qp.IllegalASTFormatException;
 import org.apache.iotdb.db.exception.qp.LogicalOperatorException;
@@ -55,6 +106,8 @@ import org.apache.iotdb.db.qp.logical.sys.DeleteTimeSeriesOperator;
 import org.apache.iotdb.db.qp.logical.sys.LoadDataOperator;
 import org.apache.iotdb.db.qp.logical.sys.PropertyOperator;
 import org.apache.iotdb.db.qp.logical.sys.SetStorageGroupOperator;
+import org.apache.iotdb.db.qp.logical.sys.SetTTLOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowTTLOperator;
 import org.apache.iotdb.db.query.fill.IFill;
 import org.apache.iotdb.db.query.fill.LinearFill;
 import org.apache.iotdb.db.query.fill.PreviousFill;
@@ -86,7 +139,7 @@ public class LogicalGenerator {
   }
 
   public RootOperator getLogicalPlan(AstNode astNode)
-      throws QueryProcessorException, ArgsErrorException, MetadataErrorException {
+      throws QueryProcessorException, MetadataErrorException {
     analyze(astNode);
     return initializedOperator;
   }
@@ -95,49 +148,48 @@ public class LogicalGenerator {
    * input an astNode parsing by {@code antlr} and analyze it.
    *
    * @throws QueryProcessorException exception in query process
-   * @throws ArgsErrorException args error
    */
   private void analyze(AstNode astNode)
-      throws QueryProcessorException, ArgsErrorException, MetadataErrorException {
+      throws QueryProcessorException, MetadataErrorException {
     Token token = astNode.getToken();
     if (token == null) {
       throw new QueryProcessorException("given token is null");
     }
     int tokenIntType = token.getType();
     switch (tokenIntType) {
-      case TqlParser.TOK_INSERT:
+      case TOK_INSERT:
         analyzeInsert(astNode);
         return;
-      case TqlParser.TOK_SELECT:
+      case TOK_SELECT:
         analyzeSelectedPath(astNode);
         return;
-      case TqlParser.TOK_FROM:
+      case TOK_FROM:
         analyzeFrom(astNode);
         return;
-      case TqlParser.TOK_WHERE:
+      case TOK_WHERE:
         analyzeWhere(astNode);
         return;
-      case TqlParser.TOK_GROUPBY:
+      case TOK_GROUPBY:
         analyzeGroupBy(astNode);
         return;
-      case TqlParser.TOK_FILL:
+      case TOK_FILL:
         analyzeFill(astNode);
         return;
-      case TqlParser.TOK_ALTER:
+      case TOK_ALTER:
         analyzeAuthorAlter(astNode);
         return;
-      case TqlParser.TOK_UPDATE:
+      case TOK_UPDATE:
         analyzeUpdate(astNode);
         return;
-      case TqlParser.TOK_DELETE:
+      case TOK_DELETE:
         switch (astNode.getChild(0).getType()) {
-          case TqlParser.TOK_TIMESERIES:
+          case TOK_TIMESERIES:
             analyzeMetadataDelete(astNode);
             break;
-          case TqlParser.TOK_LABEL:
+          case TOK_LABEL:
             analyzePropertyDeleteLabel(astNode);
             break;
-          case TqlParser.TOK_STORAGEGROUP:
+          case TOK_STORAGEGROUP:
             analyzeMetaDataDeleteFileLevel(astNode);
             break;
           default:
@@ -145,78 +197,81 @@ public class LogicalGenerator {
             break;
         }
         return;
-      case TqlParser.TOK_SET:
+      case TOK_SET:
         analyzeMetadataSetFileLevel(astNode);
         return;
-      case TqlParser.TOK_ADD:
+      case TOK_ADD:
         analyzePropertyAddLabel(astNode);
         return;
-      case TqlParser.TOK_LINK:
+      case TOK_LINK:
         analyzePropertyLink(astNode);
         return;
-      case TqlParser.TOK_UNLINK:
+      case TOK_UNLINK:
         analyzePropertyUnLink(astNode);
         return;
-      case TqlParser.TOK_CREATE:
+      case TOK_CREATE:
         switch (astNode.getChild(0).getType()) {
-          case TqlParser.TOK_USER:
-          case TqlParser.TOK_ROLE:
+          case TOK_USER:
+          case TOK_ROLE:
             analyzeAuthorCreate(astNode);
             break;
-          case TqlParser.TOK_PATH:
+          case TOK_PATH:
             analyzeMetadataCreate(astNode);
             break;
-          case TqlParser.TOK_PROPERTY:
+          case TOK_PROPERTY:
             analyzePropertyCreate(astNode);
             break;
           default:
             break;
         }
         return;
-      case TqlParser.TOK_DROP:
+      case TOK_DROP:
         switch (astNode.getChild(0).getType()) {
-          case TqlParser.TOK_USER:
-          case TqlParser.TOK_ROLE:
+          case TOK_USER:
+          case TOK_ROLE:
             analyzeAuthorDrop(astNode);
             break;
           default:
             break;
         }
         return;
-      case TqlParser.TOK_GRANT:
+      case TOK_GRANT:
         analyzeAuthorGrant(astNode);
         return;
-      case TqlParser.TOK_GRANT_WATERMARK_EMBEDDING:
+      case TOK_GRANT_WATERMARK_EMBEDDING:
         analyzeWatermarkEmbedding(astNode, SQLConstant.TOK_GRANT_WATERMARK_EMBEDDING);
         return;
-      case TqlParser.TOK_REVOKE_WATERMARK_EMBEDDING:
+      case TOK_REVOKE_WATERMARK_EMBEDDING:
         analyzeWatermarkEmbedding(astNode, SQLConstant.TOK_REVOKE_WATERMARK_EMBEDDING);
         return;
-      case TqlParser.TOK_REVOKE:
+      case TOK_REVOKE:
         analyzeAuthorRevoke(astNode);
         return;
-      case TqlParser.TOK_LOAD:
+      case TOK_LOAD:
         analyzeDataLoad(astNode);
         return;
-      case TqlParser.TOK_QUERY:
+      case TOK_QUERY:
         // for TqlParser.TOK_QUERY might appear in both query and insert
         // command. Thus, do
         // nothing and call analyze() with children nodes recursively.
         initializedOperator = new QueryOperator(SQLConstant.TOK_QUERY);
         break;
-      case TqlParser.TOK_LIST:
+      case TOK_LIST:
         analyzeList(astNode);
         return;
-      case TqlParser.TOK_LIMIT:
+      case TOK_LIMIT:
         analyzeLimit(astNode);
         return;
-      case TqlParser.TOK_SLIMIT:
+      case TOK_SLIMIT:
         analyzeSlimit(astNode);
         return;
-      case TqlParser.TOK_SOFFSET:
+      case TOK_SOFFSET:
         analyzeSoffset(astNode);
         return;
-      case TqlParser.TOK_GROUPBY_DEVICE:
+      case TOK_TTL:
+        analyzeTTL(astNode);
+        return;
+      case TOK_GROUPBY_DEVICE:
         ((QueryOperator) initializedOperator).setGroupByDevice(true);
         return;
       default:
@@ -227,6 +282,49 @@ public class LogicalGenerator {
     }
   }
 
+  private void analyzeTTL(AstNode astNode) throws QueryProcessorException {
+    int tokenType = astNode.getChild(0).getToken().getType();
+    switch (tokenType) {
+      case TOK_SET:
+        analyzeSetTTL(astNode);
+        break;
+      case TOK_UNSET:
+        analyzeUnsetTTL(astNode);
+        break;
+      case TOK_SHOW:
+        analyzeShowTTL(astNode);
+        break;
+      default:
+        throw new QueryProcessorException("Not supported TSParser type in TTL:" + tokenType);
+    }
+  }
+
+  private void analyzeSetTTL(AstNode astNode) {
+    String path = parsePath(astNode.getChild(1)).getFullPath();
+    long dataTTL;
+    dataTTL = Long.parseLong(astNode.getChild(2).getText());
+    SetTTLOperator operator = new SetTTLOperator(SQLConstant.TOK_SET);
+    initializedOperator = operator;
+    operator.setStorageGroup(path);
+    operator.setDataTTL(dataTTL);
+  }
+
+  private void analyzeUnsetTTL(AstNode astNode) {
+    String path = parsePath(astNode.getChild(1)).getFullPath();
+    SetTTLOperator operator = new SetTTLOperator(SQLConstant.TOK_UNSET);
+    initializedOperator = operator;
+    operator.setStorageGroup(path);
+  }
+
+  private void analyzeShowTTL(AstNode astNode) {
+    List<String> storageGroups = new ArrayList<>();
+    for (int i = 1; i < astNode.getChildCount(); i ++) {
+      Path path = parsePath(astNode.getChild(i));
+      storageGroups.add(path.getFullPath());
+    }
+    initializedOperator = new ShowTTLOperator(storageGroups);
+  }
+
   private void analyzeSlimit(AstNode astNode) throws LogicalOperatorException {
     AstNode unit = astNode.getChild(0);
     int seriesLimit;
@@ -284,7 +382,7 @@ public class LogicalGenerator {
 
   private void analyzeSimpleList(AstNode astNode) {
     int tokenType = astNode.getChild(0).getType();
-    if (tokenType == TqlParser.TOK_USER) {
+    if (tokenType == TOK_USER) {
       // list all users
       initializedOperator = new AuthorOperator(SQLConstant.TOK_LIST,
           AuthorOperator.AuthorType.LIST_USER);
@@ -297,31 +395,31 @@ public class LogicalGenerator {
 
   private void analyzeComplexList(AstNode astNode) {
     int tokenType = astNode.getChild(1).getType();
-    if (tokenType == TqlParser.TOK_USER) {
+    if (tokenType == TOK_USER) {
       // list user privileges on seriesPath
       AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
           AuthorOperator.AuthorType.LIST_USER_PRIVILEGE);
       initializedOperator = operator;
       operator.setUserName(astNode.getChild(1).getChild(0).getText());
       operator.setNodeNameList(parsePath(astNode.getChild(2)));
-    } else if (tokenType == TqlParser.TOK_ROLE) {
+    } else if (tokenType == TOK_ROLE) {
       // list role privileges on seriesPath
       AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
           AuthorOperator.AuthorType.LIST_ROLE_PRIVILEGE);
       initializedOperator = operator;
       operator.setRoleName(astNode.getChild(1).getChild(0).getText());
       operator.setNodeNameList(parsePath(astNode.getChild(2)));
-    } else if (tokenType == TqlParser.TOK_ALL) {
+    } else if (tokenType == TOK_ALL) {
       tokenType = astNode.getChild(0).getType();
-      if (tokenType == TqlParser.TOK_PRIVILEGES) {
+      if (tokenType == TOK_PRIVILEGES) {
         tokenType = astNode.getChild(2).getType();
-        if (tokenType == TqlParser.TOK_USER) {
+        if (tokenType == TOK_USER) {
           // list all privileges of a user
           AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
               AuthorOperator.AuthorType.LIST_USER_PRIVILEGE);
           initializedOperator = operator;
           operator.setUserName(astNode.getChild(2).getChild(0).getText());
-        } else if (tokenType == TqlParser.TOK_ROLE) {
+        } else if (tokenType == TOK_ROLE) {
           // list all privileges of a role
           AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
               AuthorOperator.AuthorType.LIST_ROLE_PRIVILEGE);
@@ -330,13 +428,13 @@ public class LogicalGenerator {
         }
       } else {
         tokenType = astNode.getChild(2).getType();
-        if (tokenType == TqlParser.TOK_USER) {
+        if (tokenType == TOK_USER) {
           // list all roles of a user
           AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
               AuthorOperator.AuthorType.LIST_USER_ROLES);
           initializedOperator = operator;
           operator.setUserName(astNode.getChild(2).getChild(0).getText());
-        } else if (tokenType == TqlParser.TOK_ROLE) {
+        } else if (tokenType == TOK_ROLE) {
           // list all users of a role
           AuthorOperator operator = new AuthorOperator(SQLConstant.TOK_LIST,
               AuthorOperator.AuthorType.LIST_ROLE_USERS);
@@ -462,10 +560,10 @@ public class LogicalGenerator {
     long timestamp;
     try {
       AstNode timeValue = astNode.getChild(2).getChild(0);
-      if (timeValue.getType() == TqlParser.TOK_DATETIME) {
-        timestamp = Long.valueOf(parseTokenTime(timeValue));
+      if (timeValue.getType() == TOK_DATETIME) {
+        timestamp = parseTimeFormat(cascadeChildrenText(timeValue));
       } else {
-        timestamp = Long.valueOf(astNode.getChild(2).getChild(0).getText());
+        timestamp = Long.parseLong(astNode.getChild(2).getChild(0).getText());
       }
     } catch (NumberFormatException e) {
       throw new LogicalOperatorException(
@@ -498,10 +596,10 @@ public class LogicalGenerator {
     }
     UpdateOperator updateOp = new UpdateOperator(SQLConstant.TOK_UPDATE);
     initializedOperator = updateOp;
-    FromOperator fromOp = new FromOperator(TqlParser.TOK_FROM);
+    FromOperator fromOp = new FromOperator(TOK_FROM);
     fromOp.addPrefixTablePath(parsePath(astNode.getChild(0)));
     updateOp.setFromOperator(fromOp);
-    SelectOperator selectOp = new SelectOperator(TqlParser.TOK_SELECT);
+    SelectOperator selectOp = new SelectOperator(TOK_SELECT);
     selectOp.addSelectPath(parsePath(astNode.getChild(1).getChild(0)));
     updateOp.setSelectOperator(selectOp);
     updateOp.setValue(astNode.getChild(1).getChild(1).getText());
@@ -514,7 +612,7 @@ public class LogicalGenerator {
     int selChildCount = astNode.getChildCount() - 1;
     for (int i = 0; i < selChildCount; i++) {
       AstNode child = astNode.getChild(i);
-      if (child.getType() != TqlParser.TOK_PATH) {
+      if (child.getType() != TOK_PATH) {
         throw new LogicalOperatorException(
             "children FROM clause except last one must all be seriesPath like root.a.b, actual:"
                 + child.getText());
@@ -556,7 +654,7 @@ public class LogicalGenerator {
     FromOperator from = new FromOperator(SQLConstant.TOK_FROM);
     for (int i = 0; i < selChildCount; i++) {
       AstNode child = node.getChild(i);
-      if (child.getType() != TqlParser.TOK_PATH) {
+      if (child.getType() != TOK_PATH) {
         throw new LogicalOperatorException(
             "children FROM clause must all be seriesPath like root.a.b, actual:" + child.getText());
       }
@@ -568,12 +666,12 @@ public class LogicalGenerator {
 
   private void analyzeSelectedPath(AstNode astNode) throws LogicalOperatorException {
     int tokenIntType = astNode.getType();
-    SelectOperator selectOp = new SelectOperator(TqlParser.TOK_SELECT);
-    if (tokenIntType == TqlParser.TOK_SELECT) {
+    SelectOperator selectOp = new SelectOperator(TOK_SELECT);
+    if (tokenIntType == TOK_SELECT) {
       int selChildCount = astNode.getChildCount();
       for (int i = 0; i < selChildCount; i++) {
         AstNode child = astNode.getChild(i);
-        if (child.getChild(0).getType() == TqlParser.TOK_AGGREGATE) {
+        if (child.getChild(0).getType() == TOK_AGGREGATE) {
           AstNode cluster = child.getChild(0);
           AstNode pathChild = cluster.getChild(0);
           Path selectPath = parsePath(pathChild);
@@ -584,7 +682,7 @@ public class LogicalGenerator {
           selectOp.addSelectPath(selectPath);
         }
       }
-    } else if (tokenIntType == TqlParser.TOK_PATH) {
+    } else if (tokenIntType == TOK_PATH) {
       Path selectPath = parsePath(astNode);
       selectOp.addSelectPath(selectPath);
     } else {
@@ -595,7 +693,7 @@ public class LogicalGenerator {
   }
 
   private void analyzeWhere(AstNode astNode) throws LogicalOperatorException {
-    if (astNode.getType() != TqlParser.TOK_WHERE) {
+    if (astNode.getType() != TOK_WHERE) {
       throw new LogicalOperatorException(
           "given node is not WHERE! please check whether SQL statement is correct.");
     }
@@ -613,10 +711,10 @@ public class LogicalGenerator {
       throws LogicalOperatorException {
     int childCount = ast.getChildCount();
     switch (tokenIntType) {
-      case TqlParser.OPERATOR_NOT:
+      case OPERATOR_NOT:
         if (childCount != 1) {
           throw new LogicalOperatorException(
-              "parsing where clause failed: NOT operator requries one param");
+              "parsing where clause failed: NOT operator requires one param");
         }
         FilterOperator notOp = new FilterOperator(SQLConstant.KW_NOT);
         filterOp.addChildOperator(notOp);
@@ -624,11 +722,11 @@ public class LogicalGenerator {
         int childNodeTokenType = childAstNode.getToken().getType();
         analyzeWhere(childAstNode, childNodeTokenType, notOp);
         break;
-      case TqlParser.OPERATOR_AND:
-      case TqlParser.OPERATOR_OR:
+      case OPERATOR_AND:
+      case OPERATOR_OR:
         if (childCount != 2) {
           throw new LogicalOperatorException(
-              "parsing where clause failed! node has " + childCount + " paramter.");
+              "parsing where clause failed! node has " + childCount + " parameter.");
         }
         FilterOperator binaryOp = new FilterOperator(
             TqlParserConstant.getTSTokenIntType(tokenIntType));
@@ -639,13 +737,13 @@ public class LogicalGenerator {
           analyzeWhere(childAstNode, childNodeTokenType, binaryOp);
         }
         break;
-      case TqlParser.OPERATOR_LT:
-      case TqlParser.OPERATOR_LTE:
-      case TqlParser.OPERATOR_EQ:
+      case OPERATOR_LT:
+      case OPERATOR_LTE:
+      case OPERATOR_EQ:
 //      case TqlParser.EQUAL_NS:
-      case TqlParser.OPERATOR_GT:
-      case TqlParser.OPERATOR_GTE:
-      case TqlParser.OPERATOR_NEQ:
+      case OPERATOR_GT:
+      case OPERATOR_GTE:
+      case OPERATOR_NEQ:
         Pair<Path, String> pair = parseLeafNode(ast);
         BasicFunctionOperator basic = new BasicFunctionOperator(
             TqlParserConstant.getTSTokenIntType(tokenIntType),
@@ -681,16 +779,16 @@ public class LogicalGenerator {
     for (int i = 0; i < intervalCount; i++) {
       intervalNode = intervalsNode.getChild(i);
       AstNode startNode = intervalNode.getChild(0);
-      if (startNode.getType() == TqlParser.TOK_DATETIME) {
-        startTime = Long.valueOf(parseTokenTime(startNode));
+      if (startNode.getType() == TOK_DATETIME) {
+        startTime = parseTokenTime(startNode);
       } else {
-        startTime = Long.valueOf(startNode.getText());
+        startTime = Long.parseLong(startNode.getText());
       }
       AstNode endNode = intervalNode.getChild(1);
-      if (endNode.getType() == TqlParser.TOK_DATETIME) {
-        endTime = Long.valueOf(parseTokenTime(endNode));
+      if (endNode.getType() == TOK_DATETIME) {
+        endTime = parseTokenTime(endNode);
       } else {
-        endTime = Long.valueOf(endNode.getText());
+        endTime = Long.parseLong(endNode.getText());
       }
       intervals.add(new Pair<>(startTime, endTime));
     }
@@ -701,10 +799,10 @@ public class LogicalGenerator {
     long originTime;
     if (childCount == 3) {
       AstNode originNode = astNode.getChild(1).getChild(0);
-      if (originNode.getType() == TqlParser.TOK_DATETIME) {
-        originTime = Long.valueOf(parseTokenTime(originNode));
+      if (originNode.getType() == TOK_DATETIME) {
+        originTime = parseTokenTime(originNode);
       } else {
-        originTime = Long.valueOf(originNode.getText());
+        originTime = Long.parseLong(originNode.getText());
       }
     } else {
       originTime = parseTimeFormat(SQLConstant.START_TIME_STR);
@@ -731,8 +829,8 @@ public class LogicalGenerator {
       TSDataType dataType = parseTypeNode(childNode.getChild(0));
       AstNode fillTypeNode = childNode.getChild(1);
       switch (fillTypeNode.getType()) {
-        case TqlParser.TOK_LINEAR:
-          checkTypeFill(dataType, TqlParser.TOK_LINEAR);
+        case TOK_LINEAR:
+          checkTypeFill(dataType, TOK_LINEAR);
           if (fillTypeNode.getChildCount() == 2) {
             long beforeRange = parseTimeUnit(fillTypeNode.getChild(0));
             long afterRange = parseTimeUnit(fillTypeNode.getChild(1));
@@ -744,8 +842,8 @@ public class LogicalGenerator {
                 "Linear fill type must have 0 or 2 valid time ranges");
           }
           break;
-        case TqlParser.TOK_PREVIOUS:
-          checkTypeFill(dataType, TqlParser.TOK_PREVIOUS);
+        case TOK_PREVIOUS:
+          checkTypeFill(dataType, TOK_PREVIOUS);
           if (fillTypeNode.getChildCount() == 1) {
             long preRange = parseTimeUnit(fillTypeNode.getChild(0));
             fillTypes.put(dataType, new PreviousFill(preRange));
@@ -771,7 +869,7 @@ public class LogicalGenerator {
       case INT64:
       case FLOAT:
       case DOUBLE:
-        if (type != TqlParser.TOK_LINEAR && type != TqlParser.TOK_PREVIOUS) {
+        if (type != TOK_LINEAR && type != TOK_PREVIOUS) {
           throw new LogicalOperatorException(
               String.format("type %s cannot use %s fill function", dataType,
                   TqlParser.tokenNames[type]));
@@ -779,7 +877,7 @@ public class LogicalGenerator {
         return;
       case BOOLEAN:
       case TEXT:
-        if (type != TqlParser.TOK_PREVIOUS) {
+        if (type != TOK_PREVIOUS) {
           throw new LogicalOperatorException(
               String.format("type %s cannot use %s fill function", dataType,
                   TqlParser.tokenNames[type]));
@@ -827,7 +925,7 @@ public class LogicalGenerator {
           "error format in SQL statement, please check whether SQL statement is correct.");
     }
     AstNode col = node.getChild(0);
-    if (col.getType() != TqlParser.TOK_PATH) {
+    if (col.getType() != TOK_PATH) {
       throw new LogicalOperatorException(
           "error format in SQL statement, please check whether SQL statement is correct.");
     }
@@ -918,7 +1016,7 @@ public class LogicalGenerator {
   /**
    * function for parsing time format.
    */
-  public long parseTimeFormat(String timestampStr) throws LogicalOperatorException {
+  long parseTimeFormat(String timestampStr) throws LogicalOperatorException {
     if (timestampStr == null || timestampStr.trim().equals("")) {
       throw new LogicalOperatorException("input timestamp cannot be empty");
     }
@@ -939,7 +1037,7 @@ public class LogicalGenerator {
     int childCount = node.getChildCount();
     String[] path;
 
-    if (childCount == 1 && node.getChild(0).getType() == TqlParser.TOK_ROOT) {
+    if (childCount == 1 && node.getChild(0).getType() == TOK_ROOT) {
       AstNode childNode = node.getChild(0);
       childCount = childNode.getChildCount();
       path = new String[childCount + 1];
@@ -958,7 +1056,7 @@ public class LogicalGenerator {
 
   private String removeStringQuote(String src) throws IllegalASTFormatException {
     if (src.length() < 3 || src.charAt(0) != '\'' || src.charAt(src.length() - 1) != '\'') {
-      throw new IllegalASTFormatException("error format for string with quoto:" + src);
+      throw new IllegalASTFormatException("error format for string with quote:" + src);
     }
     return src.substring(1, src.length() - 1);
   }
@@ -1036,12 +1134,12 @@ public class LogicalGenerator {
     if (childCount == 1) {
       // drop user or role
       switch (astNode.getChild(0).getType()) {
-        case TqlParser.TOK_USER:
+        case TOK_USER:
           authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_DROP,
               AuthorOperator.AuthorType.DROP_USER);
           authorOperator.setUserName(astNode.getChild(0).getChild(0).getText());
           break;
-        case TqlParser.TOK_ROLE:
+        case TOK_ROLE:
           authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_DROP,
               AuthorOperator.AuthorType.DROP_ROLE);
           authorOperator.setRoleName(astNode.getChild(0).getChild(0).getText());
@@ -1084,14 +1182,14 @@ public class LogicalGenerator {
         privileges[i] = removeStringQuote(privilegesNode.getChild(i).getText());
       }
       Path nodePath = parsePath(astNode.getChild(2));
-      if (astNode.getChild(0).getType() == TqlParser.TOK_USER) {
+      if (astNode.getChild(0).getType() == TOK_USER) {
         // grant user
         authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_GRANT,
             AuthorOperator.AuthorType.GRANT_USER);
         authorOperator.setUserName(astNode.getChild(0).getChild(0).getText());
         authorOperator.setPrivilegeList(privileges);
         authorOperator.setNodeNameList(nodePath);
-      } else if (astNode.getChild(0).getType() == TqlParser.TOK_ROLE) {
+      } else if (astNode.getChild(0).getType() == TOK_ROLE) {
         // grant role
         authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_GRANT,
             AuthorOperator.AuthorType.GRANT_ROLE);
@@ -1125,14 +1223,14 @@ public class LogicalGenerator {
         privileges[i] = removeStringQuote(privilegesNode.getChild(i).getText());
       }
       Path nodePath = parsePath(astNode.getChild(2));
-      if (astNode.getChild(0).getType() == TqlParser.TOK_USER) {
+      if (astNode.getChild(0).getType() == TOK_USER) {
         // revoke user
         authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_REVOKE,
             AuthorOperator.AuthorType.REVOKE_USER);
         authorOperator.setUserName(astNode.getChild(0).getChild(0).getText());
         authorOperator.setPrivilegeList(privileges);
         authorOperator.setNodeNameList(nodePath);
-      } else if (astNode.getChild(0).getType() == TqlParser.TOK_ROLE) {
+      } else if (astNode.getChild(0).getType() == TOK_ROLE) {
         // revoke role
         authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_REVOKE,
             AuthorOperator.AuthorType.REVOKE_ROLE);
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
index 0e3e513..7373956 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
@@ -32,6 +32,7 @@ import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.qp.LogicalOperatorException;
 import org.apache.iotdb.db.exception.qp.LogicalOptimizeException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.executor.IQueryProcessExecutor;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
@@ -46,6 +47,8 @@ import org.apache.iotdb.db.qp.logical.sys.DeleteTimeSeriesOperator;
 import org.apache.iotdb.db.qp.logical.sys.DeleteStorageGroupOperator;
 import org.apache.iotdb.db.qp.logical.sys.LoadDataOperator;
 import org.apache.iotdb.db.qp.logical.sys.PropertyOperator;
+import org.apache.iotdb.db.qp.logical.sys.SetTTLOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowTTLOperator;
 import org.apache.iotdb.db.qp.logical.sys.SetStorageGroupOperator;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.AggregationPlan;
@@ -61,6 +64,8 @@ import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
 import org.apache.iotdb.db.qp.physical.sys.LoadDataPlan;
 import org.apache.iotdb.db.qp.physical.sys.PropertyPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
 import org.apache.iotdb.db.service.TSServiceImpl;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -144,6 +149,19 @@ public class PhysicalGenerator {
       case QUERY:
         QueryOperator query = (QueryOperator) operator;
         return transformQuery(query);
+      case TTL:
+        switch (operator.getTokenIntType()) {
+          case SQLConstant.TOK_SET:
+            SetTTLOperator setTTLOperator = (SetTTLOperator) operator;
+            return new SetTTLPlan(setTTLOperator.getStorageGroup(), setTTLOperator.getDataTTL());
+          case SQLConstant.TOK_UNSET:
+            SetTTLOperator unsetTTLOperator = (SetTTLOperator) operator;
+            return new SetTTLPlan(unsetTTLOperator.getStorageGroup());
+          case SQLConstant.TOK_SHOW:
+            ShowTTLOperator showTTLOperator = (ShowTTLOperator) operator;
+            return new ShowTTLPlan(showTTLOperator.getStorageGroups());
+        }
+
       default:
         throw new LogicalOperatorException("not supported operator type: " + operator.getType());
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/context/QueryContext.java b/server/src/main/java/org/apache/iotdb/db/query/context/QueryContext.java
index 0f83854..b603888 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/context/QueryContext.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/context/QueryContext.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.iotdb.db.engine.modification.Modification;
 import org.apache.iotdb.db.engine.modification.ModificationFile;
+import org.apache.iotdb.tsfile.file.metadata.ChunkMetaData;
 
 /**
  * QueryContext contains the shared information with in a query.
@@ -45,6 +46,8 @@ public class QueryContext {
 
   private long jobId;
 
+  private long queryTimeLowerBound = Long.MIN_VALUE;
+
   public QueryContext() {
   }
 
@@ -87,4 +90,15 @@ public class QueryContext {
     return jobId;
   }
 
+  public long getQueryTimeLowerBound() {
+    return queryTimeLowerBound;
+  }
+
+  public void setQueryTimeLowerBound(long queryTimeLowerBound) {
+    this.queryTimeLowerBound = queryTimeLowerBound;
+  }
+
+  public boolean chunkNotSatisfy(ChunkMetaData chunkMetaData) {
+    return chunkMetaData.getEndTime() < queryTimeLowerBound;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/control/FileReaderManager.java b/server/src/main/java/org/apache/iotdb/db/query/control/FileReaderManager.java
index c34e443..67f2f52 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/control/FileReaderManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/control/FileReaderManager.java
@@ -51,23 +51,23 @@ public class FileReaderManager implements IService {
    * the key of closedFileReaderMap is the file path and the value of closedFileReaderMap
    * is the corresponding reader.
    */
-  private ConcurrentHashMap<TsFileResource, TsFileSequenceReader> closedFileReaderMap;
+  private Map<TsFileResource, TsFileSequenceReader> closedFileReaderMap;
   /**
    * the key of unclosedFileReaderMap is the file path and the value of unclosedFileReaderMap
    * is the corresponding reader.
    */
-  private ConcurrentHashMap<TsFileResource, TsFileSequenceReader> unclosedFileReaderMap;
+  private Map<TsFileResource, TsFileSequenceReader> unclosedFileReaderMap;
 
   /**
    * the key of closedFileReaderMap is the file path and the value of closedFileReaderMap
    * is the file's reference count.
    */
-  private ConcurrentHashMap<TsFileResource, AtomicInteger> closedReferenceMap;
+  private Map<TsFileResource, AtomicInteger> closedReferenceMap;
   /**
    * the key of unclosedFileReaderMap is the file path and the value of unclosedFileReaderMap
    * is the file's reference count.
    */
-  private ConcurrentHashMap<TsFileResource, AtomicInteger> unclosedReferenceMap;
+  private Map<TsFileResource, AtomicInteger> unclosedReferenceMap;
 
   private ScheduledExecutorService executorService;
 
@@ -77,7 +77,7 @@ public class FileReaderManager implements IService {
     closedReferenceMap = new ConcurrentHashMap<>();
     unclosedReferenceMap = new ConcurrentHashMap<>();
     executorService = IoTDBThreadPoolFactory.newScheduledThreadPool(1,
-        "opended-files-manager");
+        "open-files-manager");
 
     clearUnUsedFilesInFixTime();
   }
@@ -86,6 +86,19 @@ public class FileReaderManager implements IService {
     return FileReaderManagerHelper.INSTANCE;
   }
 
+  public synchronized void closeFileAndRemoveReader(TsFileResource seqFile) throws IOException {
+    closedReferenceMap.remove(seqFile);
+    TsFileSequenceReader reader = closedFileReaderMap.remove(seqFile);
+    if (reader != null) {
+      reader.close();
+    }
+    unclosedReferenceMap.remove(seqFile);
+    reader = unclosedFileReaderMap.remove(seqFile);
+    if (reader != null) {
+      reader.close();
+    }
+  }
+
   private void clearUnUsedFilesInFixTime() {
 
     long examinePeriod = IoTDBDescriptor.getInstance().getConfig().getCacheFileReaderClearPeriod();
@@ -151,7 +164,7 @@ public class FileReaderManager implements IService {
    * Increase the reference count of the reader specified by filePath. Only when the reference count
    * of a reader equals zero, the reader can be closed and removed.
    */
-  public synchronized void increaseFileReaderReference(TsFileResource tsFile, boolean isClosed) {
+  synchronized void increaseFileReaderReference(TsFileResource tsFile, boolean isClosed) {
     // TODO : this should be called in get()
     if (!isClosed) {
       unclosedReferenceMap.computeIfAbsent(tsFile, k -> new AtomicInteger()).getAndIncrement();
@@ -165,7 +178,7 @@ public class FileReaderManager implements IService {
    * Decrease the reference count of the reader specified by filePath. This method is latch-free.
    * Only when the reference count of a reader equals zero, the reader can be closed and removed.
    */
-  public synchronized void decreaseFileReaderReference(TsFileResource tsFile, boolean isClosed) {
+  synchronized void decreaseFileReaderReference(TsFileResource tsFile, boolean isClosed) {
     if (!isClosed && unclosedReferenceMap.containsKey(tsFile)) {
       unclosedReferenceMap.get(tsFile).getAndDecrement();
     } else if (closedReferenceMap.containsKey(tsFile)){
@@ -175,23 +188,6 @@ public class FileReaderManager implements IService {
   }
 
   /**
-   * This method is used when the given file path is deleted.
-   */
-  public synchronized void closeFileAndRemoveReader(TsFileResource tsFile)
-      throws IOException {
-    if (unclosedFileReaderMap.containsKey(tsFile)) {
-      unclosedReferenceMap.remove(tsFile);
-      unclosedFileReaderMap.get(tsFile).close();
-      unclosedFileReaderMap.remove(tsFile);
-    }
-    if (closedFileReaderMap.containsKey(tsFile)) {
-      closedReferenceMap.remove(tsFile);
-      closedFileReaderMap.get(tsFile).close();
-      closedFileReaderMap.remove(tsFile);
-    }
-  }
-
-  /**
    * Only for <code>EnvironmentUtils.cleanEnv</code> method. To make sure that unit tests and
    * integration tests will not conflict with each other.
    */
diff --git a/server/src/main/java/org/apache/iotdb/db/query/control/JobFileManager.java b/server/src/main/java/org/apache/iotdb/db/query/control/JobFileManager.java
index f632f85..2e3b2a1 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/control/JobFileManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/control/JobFileManager.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.query.control;
 
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
@@ -35,10 +36,10 @@ public class JobFileManager {
   /**
    * Map<jobId, Set<filePaths>>
    */
-  private ConcurrentHashMap<Long, Set<TsFileResource>> sealedFilePathsMap;
-  private ConcurrentHashMap<Long, Set<TsFileResource>> unsealedFilePathsMap;
+  private Map<Long, Set<TsFileResource>> sealedFilePathsMap;
+  private Map<Long, Set<TsFileResource>> unsealedFilePathsMap;
 
-  public JobFileManager() {
+  JobFileManager() {
     sealedFilePathsMap = new ConcurrentHashMap<>();
     unsealedFilePathsMap = new ConcurrentHashMap<>();
   }
@@ -47,7 +48,7 @@ public class JobFileManager {
    * Set job id for current request thread. When a query request is created firstly,
    * this method must be invoked.
    */
-  public void addJobId(long jobId) {
+  void addJobId(long jobId) {
     sealedFilePathsMap.computeIfAbsent(jobId, x -> new HashSet<>());
     unsealedFilePathsMap.computeIfAbsent(jobId, x -> new HashSet<>());
   }
@@ -59,13 +60,25 @@ public class JobFileManager {
   public void addUsedFilesForGivenJob(long jobId, QueryDataSource dataSource) {
 
     //sequence data
-    for(TsFileResource tsFileResource : dataSource.getSeqResources()){
-      addFilePathToMap(jobId, tsFileResource, tsFileResource.isClosed());
-    }
+    addUsedFilesForGivenJob(jobId, dataSource.getSeqResources());
 
     //unsequence data
-    for(TsFileResource tsFileResource : dataSource.getUnseqResources()){
-      addFilePathToMap(jobId, tsFileResource, tsFileResource.isClosed());
+    addUsedFilesForGivenJob(jobId, dataSource.getUnseqResources());
+  }
+
+  private void addUsedFilesForGivenJob(long jobId, List<TsFileResource> resources) {
+    for (TsFileResource tsFileResource : resources) {
+      // the file may change from open to closed within the few statements, so the initial status
+      // should be recorded to ensure consistency
+      boolean isClosed = tsFileResource.isClosed();
+      addFilePathToMap(jobId, tsFileResource, isClosed);
+      // this file may be deleted just before we lock it
+      if (tsFileResource.isDeleted()) {
+        Map<Long, Set<TsFileResource>> pathMap = !isClosed ? unsealedFilePathsMap : sealedFilePathsMap;
+        pathMap.get(jobId).remove(tsFileResource);
+        FileReaderManager.getInstance().decreaseFileReaderReference(tsFileResource, isClosed);
+        resources.remove(tsFileResource);
+      }
     }
   }
 
@@ -97,7 +110,7 @@ public class JobFileManager {
    * must not return null.
    */
   void addFilePathToMap(long jobId, TsFileResource tsFile, boolean isClosed) {
-    ConcurrentHashMap<Long, Set<TsFileResource>> pathMap = !isClosed ? unsealedFilePathsMap :
+    Map<Long, Set<TsFileResource>> pathMap = isClosed ? unsealedFilePathsMap :
         sealedFilePathsMap;
     //TODO this is not an atomic operation, is there concurrent problem?
     if (!pathMap.get(jobId).contains(tsFile)) {
diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/ListDataSet.java
similarity index 94%
rename from server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java
rename to server/src/main/java/org/apache/iotdb/db/query/dataset/ListDataSet.java
index 87fa4d6..57e3dcb 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/dataset/AuthDataSet.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/ListDataSet.java
@@ -27,12 +27,12 @@ import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
-public class AuthDataSet extends QueryDataSet {
+public class ListDataSet extends QueryDataSet {
 
   private List<RowRecord> records = new ArrayList<>();
   private int index = 0;
 
-  public AuthDataSet(List<Path> paths,
+  public ListDataSet(List<Path> paths,
       List<TSDataType> dataTypes) {
     super(paths, dataTypes);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
index 2062b78..cf8554b 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
@@ -82,6 +82,7 @@ public class GroupByWithoutValueFilterDataSet extends GroupByEngineDataSet {
     for (Path path : selectedSeries) {
       QueryDataSource queryDataSource = QueryResourceManager.getInstance()
           .getQueryDataSource(path, context);
+      timeFilter = queryDataSource.updateTimeFilter(timeFilter);
 
       // sequence reader for sealed tsfile, unsealed tsfile, memory
       IAggregateReader seqResourceIterateReader = new SeqResourceIterateReader(
diff --git a/server/src/main/java/org/apache/iotdb/db/query/executor/AggregateEngineExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/executor/AggregateEngineExecutor.java
index 1bad0a0..5cbd7a9 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/executor/AggregateEngineExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/executor/AggregateEngineExecutor.java
@@ -50,7 +50,9 @@ import org.apache.iotdb.tsfile.read.common.BatchData;
 import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.expression.IExpression;
 import org.apache.iotdb.tsfile.read.expression.impl.GlobalTimeExpression;
+import org.apache.iotdb.tsfile.read.filter.TimeFilter;
 import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+import org.apache.iotdb.tsfile.read.filter.operator.AndFilter;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
 public class AggregateEngineExecutor {
@@ -100,6 +102,8 @@ public class AggregateEngineExecutor {
 
       QueryDataSource queryDataSource = QueryResourceManager.getInstance()
           .getQueryDataSource(selectedSeries.get(i), context);
+      // add additional time filter if TTL is set
+      timeFilter = queryDataSource.updateTimeFilter(timeFilter);
 
       // sequence reader for sealed tsfile, unsealed tsfile, memory
       IAggregateReader seqResourceIterateReader;
diff --git a/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileIterateReader.java b/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileIterateReader.java
index d7dda61..b35b1bd 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileIterateReader.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileIterateReader.java
@@ -106,7 +106,7 @@ public class UnSealedTsFileIterateReader extends IterateReader {
       Filter filter)
       throws IOException {
     FileSeriesReader fileSeriesReader;
-    List<ChunkMetaData> metaDataList = unSealedTsFile.getChunkMetaDatas();
+    List<ChunkMetaData> metaDataList = unSealedTsFile.getChunkMetaDataList();
 
     if (metaDataList == null || metaDataList.isEmpty()) {
       // init fileSeriesReader
diff --git a/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderByTimestamp.java b/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderByTimestamp.java
index 7e1856a..2ac0053 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderByTimestamp.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderByTimestamp.java
@@ -67,7 +67,7 @@ public class UnSealedTsFileReaderByTimestamp implements IReaderByTimestamp {
         .get(unsealedTsFile, false);
     IChunkLoader chunkLoader = new ChunkLoaderImpl(unClosedTsFileReader);
     unSealedTsFileDiskReaderByTs = new FileSeriesReaderByTimestamp(chunkLoader,
-        unsealedTsFile.getChunkMetaDatas());
+        unsealedTsFile.getChunkMetaDataList());
 
     unSealedTsFileDiskReaderEnded = false;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceMergeReader.java b/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceMergeReader.java
index d32f080..49db4b3 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceMergeReader.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceMergeReader.java
@@ -85,7 +85,7 @@ public class UnseqResourceMergeReader extends PriorityMergeReader {
             continue;
           }
         }
-        metaDataList = tsFileResource.getChunkMetaDatas();
+        metaDataList = tsFileResource.getChunkMetaDataList();
       }
 
       ChunkLoaderImpl chunkLoader = null;
diff --git a/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderByTimestamp.java b/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderByTimestamp.java
index 8f3d28b..139e859 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderByTimestamp.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderByTimestamp.java
@@ -67,7 +67,7 @@ public class UnseqResourceReaderByTimestamp extends PriorityMergeReaderByTimesta
           QueryUtils.modifyChunkMetaData(metaDataList, pathModifications);
         }
       } else {
-        metaDataList = tsFileResource.getChunkMetaDatas();
+        metaDataList = tsFileResource.getChunkMetaDataList();
       }
 
       ChunkLoaderImpl chunkLoader = null;
diff --git a/server/src/main/java/org/apache/iotdb/db/query/reader/seriesRelated/SeriesReaderWithoutValueFilter.java b/server/src/main/java/org/apache/iotdb/db/query/reader/seriesRelated/SeriesReaderWithoutValueFilter.java
index 46093b4..d6e384b 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/reader/seriesRelated/SeriesReaderWithoutValueFilter.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/reader/seriesRelated/SeriesReaderWithoutValueFilter.java
@@ -64,25 +64,26 @@ public class SeriesReaderWithoutValueFilter implements IPointReader {
    * Constructor function.
    *
    * @param seriesPath the path of the series data
-   * @param filter filter condition
+   * @param timeFilter time filter condition
    * @param context query context
    * @param pushdownUnseq True to push down the filter on the unsequence TsFile resource; False not
    * to.
    */
-  protected SeriesReaderWithoutValueFilter(Path seriesPath, Filter filter, QueryContext context,
+  protected SeriesReaderWithoutValueFilter(Path seriesPath, Filter timeFilter, QueryContext context,
       boolean pushdownUnseq) throws StorageEngineException, IOException {
     QueryDataSource queryDataSource = QueryResourceManager.getInstance()
         .getQueryDataSource(seriesPath, context);
+    timeFilter = queryDataSource.updateTimeFilter(timeFilter);
 
     // reader for sequence resources
     IBatchReader seqResourceIterateReader = new SeqResourceIterateReader(
-        queryDataSource.getSeriesPath(), queryDataSource.getSeqResources(), filter, context);
+        queryDataSource.getSeriesPath(), queryDataSource.getSeqResources(), timeFilter, context);
 
     // reader for unsequence resources
     IPointReader unseqResourceMergeReader;
     if (pushdownUnseq) {
       unseqResourceMergeReader = new UnseqResourceMergeReader(seriesPath,
-          queryDataSource.getUnseqResources(), context, filter);
+          queryDataSource.getUnseqResources(), context, timeFilter);
     } else {
       unseqResourceMergeReader = new UnseqResourceMergeReader(seriesPath,
           queryDataSource.getUnseqResources(), context, null);
diff --git a/server/src/main/java/org/apache/iotdb/db/service/JDBCServiceEventHandler.java b/server/src/main/java/org/apache/iotdb/db/service/JDBCServiceEventHandler.java
index b913c9a..2e9ea5f 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/JDBCServiceEventHandler.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/JDBCServiceEventHandler.java
@@ -19,22 +19,17 @@
 package org.apache.iotdb.db.service;
 
 import java.util.concurrent.CountDownLatch;
-
-import org.apache.thrift.TException;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.server.ServerContext;
 import org.apache.thrift.server.TServerEventHandler;
 import org.apache.thrift.transport.TTransport;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class JDBCServiceEventHandler implements TServerEventHandler {
 
-  private static final Logger logger = LoggerFactory.getLogger(JDBCServiceEventHandler.class);
   private TSServiceImpl serviceImpl;
   private CountDownLatch startLatch;
 
-  public JDBCServiceEventHandler(TSServiceImpl serviceImpl, CountDownLatch startLatch) {
+  JDBCServiceEventHandler(TSServiceImpl serviceImpl, CountDownLatch startLatch) {
     this.serviceImpl = serviceImpl;
     this.startLatch = startLatch;
   }
@@ -47,11 +42,7 @@ public class JDBCServiceEventHandler implements TServerEventHandler {
 
   @Override
   public void deleteContext(ServerContext arg0, TProtocol arg1, TProtocol arg2) {
-    try {
-      serviceImpl.handleClientExit();
-    } catch (TException e) {
-      logger.error("failed to clear client status", e);
-    }
+    serviceImpl.handleClientExit();
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 2a05958..b337368 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -20,6 +20,8 @@ package org.apache.iotdb.db.service;
 
 import static org.apache.iotdb.db.conf.IoTDBConstant.PRIVILEGE;
 import static org.apache.iotdb.db.conf.IoTDBConstant.ROLE;
+import static org.apache.iotdb.db.conf.IoTDBConstant.STORAGE_GROUP;
+import static org.apache.iotdb.db.conf.IoTDBConstant.TTL;
 import static org.apache.iotdb.db.conf.IoTDBConstant.USER;
 
 import java.io.IOException;
@@ -53,6 +55,8 @@ import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.flush.pool.FlushTaskPoolManager;
 import org.apache.iotdb.db.exception.ArgsErrorException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
+import org.apache.iotdb.db.exception.NotStorageGroupException;
+import org.apache.iotdb.db.exception.OutOfTTLException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.QueryInBatchStmtException;
@@ -61,7 +65,6 @@ import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.exception.qp.IllegalASTFormatException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 import org.apache.iotdb.db.metadata.MManager;
-import org.apache.iotdb.db.metadata.Metadata;
 import org.apache.iotdb.db.metrics.server.SqlArgument;
 import org.apache.iotdb.db.qp.QueryProcessor;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
@@ -74,6 +77,7 @@ import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
@@ -152,7 +156,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
   // TODO: remove unclosed statements
   private Map<Long, PhysicalPlan> idStmtMap = new ConcurrentHashMap<>();
 
-  public TSServiceImpl() throws IOException {
+  public TSServiceImpl() {
     processor = new QueryProcessor(new QueryProcessExecutor());
   }
 
@@ -274,10 +278,8 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
    * @param statusType status type
    */
   private TSStatus getStatus(TSStatusCode statusType) {
-    TSStatusType statusCodeAndMessage = new TSStatusType(statusType.getStatusCode(),
-        statusType.getStatusMessage());
-    TSStatus status = new TSStatus(statusCodeAndMessage);
-    return status;
+    TSStatusType statusCodeAndMessage = new TSStatusType(statusType.getStatusCode(), statusType.getStatusMessage());
+    return new TSStatus(statusCodeAndMessage);
   }
 
   /**
@@ -288,9 +290,8 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
    */
   private TSStatus getStatus(TSStatusCode statusType, String appendMessage) {
     TSStatusType statusCodeAndMessage = new TSStatusType(statusType.getStatusCode(),
-        statusType.getStatusMessage() + ": " + appendMessage);
-    TSStatus status = new TSStatus(statusCodeAndMessage);
-    return status;
+            statusType.getStatusMessage() + ": " + appendMessage);
+    return new TSStatus(statusCodeAndMessage);
   }
 
   @Override
@@ -311,7 +312,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
         case "SHOW_STORAGE_GROUP":
-          Set<String> storageGroups = getAllStorageGroups();
+          Set<String> storageGroups = new HashSet<>(getAllStorageGroups());
           resp.setStorageGroups(storageGroups);
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
@@ -371,15 +372,15 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     return nodeColumnsNum;
   }
 
-  private List<String> getNodesList(String schemaPattern, int level) throws PathErrorException, SQLException {
+  private List<String> getNodesList(String schemaPattern, int level) throws SQLException {
     return MManager.getInstance().getNodesList(schemaPattern, level);
   }
 
-  private Set<String> getAllStorageGroups() throws PathErrorException {
-    return MManager.getInstance().getAllStorageGroup();
+  private List<String> getAllStorageGroups() {
+    return MManager.getInstance().getAllStorageGroupNames();
   }
 
-  private Set<String> getAllDevices() throws PathErrorException, SQLException {
+  private Set<String> getAllDevices() throws SQLException {
     return MManager.getInstance().getAllDevices();
   }
 
@@ -392,19 +393,17 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     return MManager.getInstance().getMetadataInString();
   }
 
-  protected Metadata getMetadata()
-      throws PathErrorException {
-    return MManager.getInstance().getMetadata();
-  }
-
   public static TSDataType getSeriesType(String path)
       throws PathErrorException {
     switch (path.toLowerCase()) {
       // authorization queries
-      case "role":
-      case "user":
-      case "privilege":
+      case ROLE:
+      case USER:
+      case PRIVILEGE:
+      case STORAGE_GROUP:
         return TSDataType.TEXT;
+      case TTL:
+        return TSDataType.INT64;
       default:
         // do nothing
     }
@@ -445,7 +444,6 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
    *
    * @param statement command
    * @return true if the statement is ADMIN COMMAND
-   * @throws IOException exception
    */
   private boolean execAdminCommand(String statement) throws StorageEngineException {
     if (!"root".equals(username.get())) {
@@ -528,9 +526,8 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
       }
     } catch (Exception e) {
       String errMessage = String.format(
-          "Fail to generate physcial plan and execute for statement "
-              + "%s beacuse %s",
-          statement, e.getMessage());
+          "Fail to generate physical plan and execute for statement "
+              + "%s because %s", statement, e.getMessage());
       logger.warn("Error occurred when executing {}", statement, e);
       result.add(Statement.EXECUTE_FAILED);
       batchErrorMessage.append(errMessage).append("\n");
@@ -574,7 +571,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
             IoTDBDescriptor.getInstance().getConfig().getMaxMemtableNumber(),
             IoTDBDescriptor.getInstance().getConfig().getTsFileSizeThreshold(),
             CompressionRatio.getInstance().getRatio(),
-            MManager.getInstance().getAllStorageGroup().size(),
+            MManager.getInstance().getAllStorageGroupNames().size(),
             IoTDBConfigDynamicAdapter.getInstance().getTotalTimeseries(),
             MManager.getInstance().getMaximalSeriesNumberAmongStorageGroups());
         return getTSExecuteStatementResp(getStatus(TSStatusCode.SUCCESS_STATUS, msg));
@@ -620,11 +617,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
       return false;
     }
     statement = statement.toLowerCase().trim();
-    if (Pattern.matches(IoTDBConstant.SHOW_FLUSH_TASK_INFO, statement)) {
-      return true;
-    } else {
-      return false;
-    }
+    return Pattern.matches(IoTDBConstant.SHOW_FLUSH_TASK_INFO, statement);
   }
 
   /**
@@ -635,11 +628,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
       return false;
     }
     statement = statement.toLowerCase().trim();
-    if (Pattern.matches(IoTDBConstant.SHOW_DYNAMIC_PARAMETERS, statement)) {
-      return true;
-    } else {
-      return false;
-    }
+    return Pattern.matches(IoTDBConstant.SHOW_DYNAMIC_PARAMETERS, statement);
   }
 
   /**
@@ -662,10 +651,12 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     long t1 = System.currentTimeMillis();
     try {
       TSExecuteStatementResp resp;
-      if (!(plan instanceof AuthorPlan)) {
-        resp = executeDataQuery(plan);
-      } else {
+      if (plan instanceof AuthorPlan) {
         resp = executeAuthQuery(plan);
+      } else if(plan instanceof ShowTTLPlan) {
+        resp = executeShowTTL();
+      } else {
+        resp = executeDataQuery(plan);
       }
       if (plan.getOperatorType() == OperatorType.AGGREGATION) {
         resp.setIgnoreTimeStamp(true);
@@ -718,6 +709,22 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     return columnTypes;
   }
 
+
+  private TSExecuteStatementResp executeShowTTL() {
+    TSExecuteStatementResp resp =
+        getTSExecuteStatementResp(getStatus(TSStatusCode.SUCCESS_STATUS));
+    resp.setIgnoreTimeStamp(true);
+    List<String> columns = new ArrayList<>();
+    List<String> columnTypes = new ArrayList<>();
+    columns.add(STORAGE_GROUP);
+    columns.add(TTL);
+    columnTypes.add(TSDataType.TEXT.toString());
+    columnTypes.add(TSDataType.INT64.toString());
+    resp.setColumns(columns);
+    resp.setDataTypeList(columnTypes);
+    return resp;
+  }
+
   private TSExecuteStatementResp executeAuthQuery(PhysicalPlan plan) {
     TSExecuteStatementResp resp = getTSExecuteStatementResp(getStatus(TSStatusCode.SUCCESS_STATUS));
     resp.setIgnoreTimeStamp(true);
@@ -726,21 +733,15 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     List<String> columnsType = new ArrayList<>();
     switch (authorPlan.getAuthorType()) {
       case LIST_ROLE:
+      case LIST_USER_ROLES:
         columnsName.add(ROLE);
         columnsType.add(TSDataType.TEXT.toString());
         break;
       case LIST_USER:
-        columnsName.add(USER);
-        columnsType.add(TSDataType.TEXT.toString());
-        break;
       case LIST_ROLE_USERS:
         columnsName.add(USER);
         columnsType.add(TSDataType.TEXT.toString());
         break;
-      case LIST_USER_ROLES:
-        columnsName.add(ROLE);
-        columnsType.add(TSDataType.TEXT.toString());
-        break;
       case LIST_ROLE_PRIVILEGE:
         columnsName.add(PRIVILEGE);
         columnsType.add(TSDataType.TEXT.toString());
@@ -1054,7 +1055,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     return resp;
   }
 
-  void handleClientExit() throws TException {
+  void handleClientExit() {
     closeOperation(null);
     closeSession(null);
   }
@@ -1135,7 +1136,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
   }
 
   @Override
-  public TSStatus insertRow(TSInsertReq req) throws TException {
+  public TSStatus insertRow(TSInsertReq req) {
     if (!checkLogin()) {
       logger.info(INFO_NOT_LOGIN, IoTDBConstant.GLOBAL_DB_NAME);
       return new TSStatus(getStatus(TSStatusCode.NOT_LOGIN_ERROR));
@@ -1227,7 +1228,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
   }
 
   @Override
-  public TSStatus setStorageGroup(String storageGroup) throws TException {
+  public TSStatus setStorageGroup(String storageGroup) {
     if (!checkLogin()) {
       logger.info(INFO_NOT_LOGIN, IoTDBConstant.GLOBAL_DB_NAME);
       return new TSStatus(getStatus(TSStatusCode.NOT_LOGIN_ERROR));
@@ -1267,7 +1268,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     }
     CreateTimeSeriesPlan plan = new CreateTimeSeriesPlan(new Path(req.getPath()),
         TSDataType.values()[req.getDataType()], TSEncoding.values()[req.getEncoding()],
-        CompressionType.values()[req.compressor], new HashMap<String, String>());
+        CompressionType.values()[req.compressor], new HashMap<>());
     TSStatus status = checkAuthority(plan);
     if (status != null) {
       return new TSStatus(status);
@@ -1320,7 +1321,13 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
       execRet = executeNonQuery(plan);
     } catch (ProcessorException e) {
       logger.debug("meet error while processing non-query. ", e);
-      return getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, e.getMessage());
+      if (e.getCause() instanceof OutOfTTLException) {
+        return getStatus(TSStatusCode.OUT_OF_TTL_ERROR, e.getMessage());
+      } else if (e.getCause() instanceof NotStorageGroupException) {
+        return getStatus(TSStatusCode.NOT_A_STORAGE_GROUP_ERROR, e.getMessage());
+      } else {
+        return getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, e.getMessage());
+      }
     }
 
     return execRet ? getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully")
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java b/server/src/main/java/org/apache/iotdb/db/utils/TestOnly.java
similarity index 71%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
copy to server/src/main/java/org/apache/iotdb/db/utils/TestOnly.java
index dd27fc5..d4058ba 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBSQLException.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/TestOnly.java
@@ -15,22 +15,17 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
 
-package org.apache.iotdb.jdbc;
-
-import java.sql.SQLException;
-
-public class IoTDBSQLException extends SQLException {
-
-  private static final long serialVersionUID = -3306001287342258977L;
-
-  public IoTDBSQLException(String reason) {
-    super(reason);
-  }
+package org.apache.iotdb.db.utils;
 
-  public IoTDBSQLException(Throwable cause) {
-    super(cause);
-  }
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@Retention(RetentionPolicy.SOURCE)
+public @interface TestOnly {
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/memtable/PrimitiveMemTableTest.java b/server/src/test/java/org/apache/iotdb/db/engine/memtable/PrimitiveMemTableTest.java
index 01f1fb9..fb561bd 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/memtable/PrimitiveMemTableTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/memtable/PrimitiveMemTableTest.java
@@ -80,7 +80,7 @@ public class PrimitiveMemTableTest {
       memTable.write(deviceId, measurementId[0], TSDataType.INT32, i, String.valueOf(i));
     }
     Iterator<TimeValuePair> tvPair = memTable
-        .query(deviceId, measurementId[0], TSDataType.INT32, Collections.emptyMap())
+        .query(deviceId, measurementId[0], TSDataType.INT32, Collections.emptyMap(), Long.MIN_VALUE)
         .getSortedTimeValuePairList().iterator();
     for (int i = 0; i < dataSize; i++) {
       TimeValuePair timeValuePair = tvPair.next();
@@ -98,7 +98,7 @@ public class PrimitiveMemTableTest {
           ret[i].getValue().getStringValue());
     }
     Iterator<TimeValuePair> tvPair = memTable
-        .query(deviceId, sensorId, dataType, Collections.emptyMap())
+        .query(deviceId, sensorId, dataType, Collections.emptyMap(), Long.MIN_VALUE)
         .getSortedTimeValuePairList()
         .iterator();
     Arrays.sort(ret);
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
index f3f6b5c..df6ad32 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
@@ -19,7 +19,6 @@
 
 package org.apache.iotdb.db.engine.modification;
 
-import static junit.framework.TestCase.assertTrue;
 import static org.apache.iotdb.db.utils.EnvironmentUtils.TEST_QUERY_CONTEXT;
 import static org.apache.iotdb.db.utils.EnvironmentUtils.TEST_QUERY_JOB_ID;
 import static org.junit.Assert.assertEquals;
@@ -29,6 +28,7 @@ import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
+import junit.framework.TestCase;
 import org.apache.iotdb.db.conf.directories.DirectoryManager;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.modification.io.LocalTextModificationAccessor;
@@ -125,7 +125,8 @@ public class DeletionFileNodeTest {
   }
 
   @Test
-  public void testDeleteInBufferWriteFile() throws StorageEngineException, IOException {
+  public void testDeleteInBufferWriteFile()
+      throws StorageEngineException, IOException, ProcessorException {
     for (int i = 1; i <= 100; i++) {
       TSRecord record = new TSRecord(i, processorName);
       for (int j = 0; j < 10; j++) {
@@ -157,7 +158,7 @@ public class DeletionFileNodeTest {
       assertEquals(3, modifications.size());
       int i = 0;
       for (Modification modification : modifications) {
-        assertTrue(modification.equals(realModifications[i++]));
+        TestCase.assertEquals(modification, realModifications[i++]);
       }
     } finally {
       accessor.close();
@@ -209,7 +210,8 @@ public class DeletionFileNodeTest {
   }
 
   @Test
-  public void testDeleteInOverflowFile() throws StorageEngineException, IOException {
+  public void testDeleteInOverflowFile()
+      throws StorageEngineException, ProcessorException {
     // insert into BufferWrite
     for (int i = 101; i <= 200; i++) {
       TSRecord record = new TSRecord(i, processorName);
@@ -251,7 +253,7 @@ public class DeletionFileNodeTest {
     assertEquals( 3, modifications.size());
     int i = 0;
     for (Modification modification : modifications) {
-      assertTrue(modification.equals(realModifications[i++]));
+      TestCase.assertEquals(modification, realModifications[i++]);
     }
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
index 674d924..c054c21 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
@@ -29,6 +29,7 @@ import java.util.List;
 import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
+import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StartupException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.StorageGroupException;
@@ -41,7 +42,6 @@ import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.common.Path;
-import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.read.expression.QueryExpression;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 import org.apache.iotdb.tsfile.write.record.TSRecord;
@@ -88,7 +88,7 @@ public class  DeletionQueryTest {
 
   @Test
   public void testDeleteInBufferWriteCache() throws
-      StorageEngineException, IOException {
+      StorageEngineException, IOException, ProcessorException {
 
     for (int i = 1; i <= 100; i++) {
       TSRecord record = new TSRecord(i, processorName);
@@ -120,7 +120,8 @@ public class  DeletionQueryTest {
   }
 
   @Test
-  public void testDeleteInBufferWriteFile() throws StorageEngineException, IOException {
+  public void testDeleteInBufferWriteFile()
+      throws StorageEngineException, IOException, ProcessorException {
     for (int i = 1; i <= 100; i++) {
       TSRecord record = new TSRecord(i, processorName);
       for (int j = 0; j < 10; j++) {
@@ -151,7 +152,8 @@ public class  DeletionQueryTest {
   }
 
   @Test
-  public void testDeleteInOverflowCache() throws StorageEngineException, IOException {
+  public void testDeleteInOverflowCache()
+      throws StorageEngineException, IOException, ProcessorException {
     // insert into BufferWrite
     for (int i = 101; i <= 200; i++) {
       TSRecord record = new TSRecord(i, processorName);
@@ -186,14 +188,15 @@ public class  DeletionQueryTest {
 
     int count = 0;
     while (dataSet.hasNext()) {
-      RowRecord record = dataSet.next();
+      dataSet.next();
       count++;
     }
     assertEquals(150, count);
   }
 
   @Test
-  public void testDeleteInOverflowFile() throws StorageEngineException, IOException {
+  public void testDeleteInOverflowFile()
+      throws StorageEngineException, IOException, ProcessorException {
     // insert into BufferWrite
     for (int i = 101; i <= 200; i++) {
       TSRecord record = new TSRecord(i, processorName);
@@ -236,7 +239,7 @@ public class  DeletionQueryTest {
 
   @Test
   public void testSuccessiveDeletion()
-      throws StorageEngineException, IOException, InterruptedException {
+      throws StorageEngineException, IOException, ProcessorException {
     for (int i = 1; i <= 100; i++) {
       TSRecord record = new TSRecord(i, processorName);
       for (int j = 0; j < 10; j++) {
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/FileNodeManagerBenchmark.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/FileNodeManagerBenchmark.java
index 093eb6a..2dd8584 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/FileNodeManagerBenchmark.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/FileNodeManagerBenchmark.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicLong;
 import org.apache.iotdb.db.engine.StorageEngine;
+import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
@@ -40,11 +41,11 @@ import org.apache.iotdb.tsfile.write.record.datapoint.LongDataPoint;
  */
 public class FileNodeManagerBenchmark {
 
-  private static int numOfWoker = 10;
+  private static int numOfWorker = 10;
   private static int numOfDevice = 10;
   private static int numOfMeasurement = 10;
   private static long numOfTotalLine = 10000000;
-  private static CountDownLatch latch = new CountDownLatch(numOfWoker);
+  private static CountDownLatch latch = new CountDownLatch(numOfWorker);
   private static AtomicLong atomicLong = new AtomicLong();
 
   private static String[] devices = new String[numOfDevice];
@@ -85,12 +86,13 @@ public class FileNodeManagerBenchmark {
     tearDown();
     prepare();
     long startTime = System.currentTimeMillis();
-    for (int i = 0; i < numOfWoker; i++) {
-      Woker woker = new Woker();
-      woker.start();
+    for (int i = 0; i < numOfWorker; i++) {
+      Worker worker = new Worker();
+      worker.start();
     }
     latch.await();
     long endTime = System.currentTimeMillis();
+    System.out.println("Elapsed time: " + (endTime - startTime) + "ms");
     tearDown();
   }
 
@@ -102,7 +104,7 @@ public class FileNodeManagerBenchmark {
     return tsRecord;
   }
 
-  private static class Woker extends Thread {
+  private static class Worker extends Thread {
 
     @Override
     public void run() {
@@ -117,7 +119,7 @@ public class FileNodeManagerBenchmark {
           TSRecord tsRecord = getRecord(deltaObject, time);
           StorageEngine.getInstance().insert(new InsertPlan(tsRecord));
         }
-      } catch (StorageEngineException e) {
+      } catch (ProcessorException e) {
         e.printStackTrace();
       } finally {
         latch.countDown();
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
index 6a5362f..07e21e9 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
@@ -21,21 +21,17 @@ package org.apache.iotdb.db.engine.storagegroup;
 import static org.junit.Assert.assertFalse;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.ArrayList;
-
 import org.apache.iotdb.db.engine.MetadataManagerHelper;
 import org.apache.iotdb.db.engine.merge.manage.MergeManager;
 import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
-
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 import org.apache.iotdb.db.qp.physical.crud.BatchInsertPlan;
-
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
-import org.apache.iotdb.db.query.control.JobFileManager;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.write.record.TSRecord;
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java
new file mode 100644
index 0000000..4bcbcc0
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.engine.storagegroup;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.directories.DirectoryManager;
+import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
+import org.apache.iotdb.db.exception.ArgsErrorException;
+import org.apache.iotdb.db.exception.MetadataErrorException;
+import org.apache.iotdb.db.exception.OutOfTTLException;
+import org.apache.iotdb.db.exception.PathErrorException;
+import org.apache.iotdb.db.exception.ProcessorException;
+import org.apache.iotdb.db.exception.StartupException;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.StorageGroupException;
+import org.apache.iotdb.db.exception.qp.QueryProcessorException;
+import org.apache.iotdb.db.metadata.MManager;
+import org.apache.iotdb.db.metadata.MNode;
+import org.apache.iotdb.db.qp.QueryProcessor;
+import org.apache.iotdb.db.qp.executor.QueryProcessExecutor;
+import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
+import org.apache.iotdb.db.query.control.QueryResourceManager;
+import org.apache.iotdb.db.query.reader.resourceRelated.SeqResourceIterateReader;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.BatchData;
+import org.apache.iotdb.tsfile.read.common.Path;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TTLTest {
+
+  private String sg1 = "root.TTL_SG1";
+  private String sg2 = "root.TTL_SG2";
+  private long ttl = 12345;
+  private StorageGroupProcessor storageGroupProcessor;
+  private String s1 = "s1";
+  private String g1s1 = sg1 + IoTDBConstant.PATH_SEPARATOR + s1;
+
+  @Before
+  public void setUp()
+      throws MetadataErrorException, ProcessorException, IOException, StartupException, PathErrorException {
+    EnvironmentUtils.envSetUp();
+    createSchemas();
+  }
+
+  @After
+  public void tearDown() throws IOException, StorageEngineException {
+    storageGroupProcessor.waitForAllCurrentTsFileProcessorsClosed();
+    EnvironmentUtils.cleanEnv();
+  }
+
+  private void createSchemas() throws MetadataErrorException, ProcessorException, PathErrorException {
+    MManager.getInstance().setStorageGroupToMTree(sg1);
+    MManager.getInstance().setStorageGroupToMTree(sg2);
+    storageGroupProcessor = new StorageGroupProcessor(IoTDBDescriptor.getInstance().getConfig()
+        .getSystemDir(), sg1);
+    MManager.getInstance().addPathToMTree(g1s1, TSDataType.INT64, TSEncoding.PLAIN,
+        CompressionType.UNCOMPRESSED, Collections.emptyMap());
+    storageGroupProcessor.addMeasurement("s1", TSDataType.INT64, TSEncoding.PLAIN,
+        CompressionType.UNCOMPRESSED, Collections.emptyMap());
+  }
+
+  @Test
+  public void testSetMetaTTL() throws IOException, PathErrorException, StorageGroupException {
+    // exception is expected when setting ttl to a non-exist storage group
+    boolean caught = false;
+    try {
+      MManager.getInstance().setTTL(sg1 + ".notExist", ttl);
+    } catch (PathErrorException e) {
+      caught = true;
+    }
+    assertTrue(caught);
+
+    // normally set ttl
+    MManager.getInstance().setTTL(sg1, ttl);
+    MNode mNode = MManager.getInstance().getNodeByPathWithCheck(sg1);
+    assertEquals(ttl, mNode.getDataTTL());
+
+    // default ttl
+    mNode = MManager.getInstance().getNodeByPathWithCheck(sg2);
+    assertEquals(Long.MAX_VALUE, mNode.getDataTTL());
+  }
+
+  @Test
+  public void testTTLWrite() throws QueryProcessorException {
+    InsertPlan insertPlan = new InsertPlan();
+    insertPlan.setDeviceId(sg1);
+    insertPlan.setTime(System.currentTimeMillis());
+    insertPlan.setMeasurements(new String[]{"s1"});
+    insertPlan.setValues(new String[]{"1"});
+    insertPlan.setDataTypes(new TSDataType[]{TSDataType.INT64});
+
+    // ok without ttl
+    assertTrue(storageGroupProcessor.insert(insertPlan));
+
+    storageGroupProcessor.setDataTTL(1000);
+    // with ttl
+    insertPlan.setTime(System.currentTimeMillis() - 1001);
+    boolean caught = false;
+    try {
+      storageGroupProcessor.insert(insertPlan);
+    } catch (OutOfTTLException e) {
+      caught = true;
+    }
+    assertTrue(caught);
+    insertPlan.setTime(System.currentTimeMillis() - 900);
+    assertTrue(storageGroupProcessor.insert(insertPlan));
+  }
+
+  private void prepareData() throws QueryProcessorException {
+    InsertPlan insertPlan = new InsertPlan();
+    insertPlan.setDeviceId(sg1);
+    insertPlan.setTime(System.currentTimeMillis());
+    insertPlan.setMeasurements(new String[]{"s1"});
+    insertPlan.setValues(new String[]{"1"});
+    insertPlan.setDataTypes(new TSDataType[]{TSDataType.INT64});
+
+    long initTime = System.currentTimeMillis();
+    // sequence data
+    for (int i = 1000; i < 2000; i++) {
+      insertPlan.setTime(initTime - 2000 + i);
+      assertTrue(storageGroupProcessor.insert(insertPlan));
+      if ((i + 1) % 300 == 0) {
+        storageGroupProcessor.putAllWorkingTsFileProcessorIntoClosingList();
+      }
+    }
+    // unsequence data
+    for (int i = 0; i < 1000; i++) {
+      insertPlan.setTime(initTime - 2000 + i);
+      storageGroupProcessor.insert(insertPlan);
+      if ((i + 1) % 300 == 0) {
+        storageGroupProcessor.putAllWorkingTsFileProcessorIntoClosingList();
+      }
+    }
+  }
+
+  @Test
+  public void testTTLRead() throws IOException, QueryProcessorException, StorageEngineException {
+    prepareData();
+
+    // files before ttl
+    QueryDataSource dataSource = storageGroupProcessor.query(sg1, s1, EnvironmentUtils.TEST_QUERY_CONTEXT
+        , null);
+    List<TsFileResource> seqResource = dataSource.getSeqResources();
+    List<TsFileResource> unseqResource = dataSource.getUnseqResources();
+    assertEquals(4, seqResource.size());
+    assertEquals(4, unseqResource.size());
+
+    storageGroupProcessor.setDataTTL(500);
+
+    // files after ttl
+    dataSource = storageGroupProcessor.query(sg1, s1, EnvironmentUtils.TEST_QUERY_CONTEXT
+        , null);
+    seqResource = dataSource.getSeqResources();
+    unseqResource = dataSource.getUnseqResources();
+    assertTrue(seqResource.size() < 4);
+    assertEquals(0, unseqResource.size());
+    Path path = new Path(sg1, s1);
+    SeqResourceIterateReader reader = new SeqResourceIterateReader(path,
+        seqResource, null, EnvironmentUtils.TEST_QUERY_CONTEXT);
+
+    int cnt = 0;
+    while (reader.hasNext()) {
+      BatchData batchData = reader.nextBatch();
+      while (batchData.hasNext()) {
+        batchData.next();
+        cnt ++;
+      }
+    }
+    reader.close();
+    // we cannot offer the exact number since when exactly ttl will be checked is unknown
+    assertTrue(cnt <= 1000);
+
+    storageGroupProcessor.setDataTTL(0);
+    dataSource = storageGroupProcessor.query(sg1, s1, EnvironmentUtils.TEST_QUERY_CONTEXT
+        , null);
+    seqResource = dataSource.getSeqResources();
+    unseqResource = dataSource.getUnseqResources();
+    assertEquals(0, seqResource.size());
+    assertEquals(0, unseqResource.size());
+
+
+    QueryResourceManager.getInstance().endQueryForGivenJob(EnvironmentUtils.TEST_QUERY_JOB_ID);
+  }
+
+  @Test
+  public void testTTLRemoval() throws StorageEngineException, QueryProcessorException {
+    prepareData();
+
+    storageGroupProcessor.waitForAllCurrentTsFileProcessorsClosed();
+
+    // files before ttl
+    File seqDir = new File(DirectoryManager.getInstance().getNextFolderForSequenceFile(), sg1);
+    File unseqDir = new File(DirectoryManager.getInstance().getNextFolderForUnSequenceFile(), sg1);
+    File[] seqFiles = seqDir.listFiles(f -> f.getName().endsWith(TsFileConstant.TSFILE_SUFFIX));
+    File[] unseqFiles = unseqDir.listFiles(f -> f.getName().endsWith(TsFileConstant.TSFILE_SUFFIX));
+
+    assertEquals(4, seqFiles.length);
+    assertEquals(4, unseqFiles.length);
+
+    storageGroupProcessor.setDataTTL(500);
+    storageGroupProcessor.checkFilesTTL();
+
+    // files after ttl
+    seqFiles = seqDir.listFiles(f -> f.getName().endsWith(TsFileConstant.TSFILE_SUFFIX));
+    unseqFiles = unseqDir.listFiles(f -> f.getName().endsWith(TsFileConstant.TSFILE_SUFFIX));
+    assertTrue(seqFiles.length <= 2);
+    assertEquals(0, unseqFiles.length);
+  }
+
+  @Test
+  public void testParseSetTTL()
+      throws ArgsErrorException, MetadataErrorException, QueryProcessorException {
+    QueryProcessor queryProcessor = new QueryProcessor(new QueryProcessExecutor());
+    SetTTLPlan plan = (SetTTLPlan) queryProcessor.parseSQLToPhysicalPlan("SET TTL TO " + sg1 + " 10000");
+    assertEquals(sg1, plan.getStorageGroup());
+    assertEquals(10000, plan.getDataTTL());
+
+    plan = (SetTTLPlan) queryProcessor.parseSQLToPhysicalPlan("UNSET TTL TO " + sg2);
+    assertEquals(sg2, plan.getStorageGroup());
+    assertEquals(Long.MAX_VALUE, plan.getDataTTL());
+  }
+
+  @Test
+  public void testParseShowTTL()
+      throws ArgsErrorException, MetadataErrorException, QueryProcessorException {
+    QueryProcessor queryProcessor = new QueryProcessor(new QueryProcessExecutor());
+    ShowTTLPlan plan = (ShowTTLPlan) queryProcessor.parseSQLToPhysicalPlan("SHOW ALL TTL");
+    assertTrue(plan.getStorageGroups().isEmpty());
+
+    List<String> sgs = new ArrayList<>();
+    sgs.add("root.sg1");
+    sgs.add("root.sg2");
+    sgs.add("root.sg3");
+    plan = (ShowTTLPlan) queryProcessor.parseSQLToPhysicalPlan("SHOW TTL ON root.sg1,root.sg2,root.sg3");
+    assertEquals(sgs, plan.getStorageGroups());
+  }
+
+  @Test
+  public void testShowTTL()
+      throws IOException, PathErrorException, ProcessorException, QueryFilterOptimizationException, StorageEngineException {
+    MManager.getInstance().setTTL(sg1, ttl);
+
+    ShowTTLPlan plan = new ShowTTLPlan(Collections.emptyList());
+    QueryProcessExecutor executor = new QueryProcessExecutor();
+    QueryDataSet queryDataSet = executor.processQuery(plan, EnvironmentUtils.TEST_QUERY_CONTEXT);
+    RowRecord rowRecord = queryDataSet.next();
+    assertEquals(sg2, rowRecord.getFields().get(0).getStringValue());
+    assertEquals("null", rowRecord.getFields().get(1).getStringValue());
+
+    rowRecord = queryDataSet.next();
+    assertEquals(sg1, rowRecord.getFields().get(0).getStringValue());
+    assertEquals(ttl, rowRecord.getFields().get(1).getLongV());
+  }
+
+  @Test
+  public void testTTLCleanFile() throws QueryProcessorException {
+    prepareData();
+    storageGroupProcessor.waitForAllCurrentTsFileProcessorsClosed();
+
+    assertEquals(4, storageGroupProcessor.getSequenceFileList().size());
+    assertEquals(4, storageGroupProcessor.getUnSequenceFileList().size());
+
+    storageGroupProcessor.setDataTTL(0);
+    assertEquals(0, storageGroupProcessor.getSequenceFileList().size());
+    assertEquals(0, storageGroupProcessor.getUnSequenceFileList().size());
+  }
+}
\ No newline at end of file
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorTest.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorTest.java
index 2330176..5079899 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorTest.java
@@ -60,12 +60,13 @@ public class TsFileProcessorTest {
   private String measurementId = "s0";
   private TSDataType dataType = TSDataType.INT32;
   private Map<String, String> props = Collections.emptyMap();
-  private QueryContext context = EnvironmentUtils.TEST_QUERY_CONTEXT;
+  private QueryContext context;
 
   @Before
   public void setUp() throws Exception {
     MetadataManagerHelper.initMetadata();
     EnvironmentUtils.envSetUp();
+    context = EnvironmentUtils.TEST_QUERY_CONTEXT;
   }
 
   @After
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTimeZoneIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTimeZoneIT.java
index bb4ab93..2b8a274 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTimeZoneIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTimeZoneIT.java
@@ -43,25 +43,25 @@ public class IoTDBTimeZoneIT {
   private final String tz1 = "root.timezone.tz1";
 
   // private boolean testFlag = TestUtils.testFlag;
-  String[] retArray = new String[]{"1514775603000,4", "1514779200000,1", "1514779201000,2",
+  private String[] retArray = new String[]{"1514775603000,4", "1514779200000,1", "1514779201000,2",
       "1514779202000,3",
       "1514779203000,8", "1514782804000,5", "1514782805000,7", "1514782806000,9",
       "1514782807000,10",
       "1514782808000,11", "1514782809000,12", "1514782810000,13", "1514789200000,6",};
-  private IoTDB deamon;
+  private IoTDB daemon;
 
   @Before
   public void setUp() throws Exception {
     EnvironmentUtils.closeStatMonitor();
-    deamon = IoTDB.getInstance();
-    deamon.active();
+    daemon = IoTDB.getInstance();
+    daemon.active();
     EnvironmentUtils.envSetUp();
     createTimeseries();
   }
 
   @After
   public void tearDown() throws Exception {
-    deamon.stop();
+    daemon.stop();
     EnvironmentUtils.cleanEnv();
   }
 
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
new file mode 100644
index 0000000..f7c0f2e
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
@@ -0,0 +1,205 @@
+/*
+ * 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.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.jdbc.Config;
+import org.apache.iotdb.jdbc.IoTDBConnection;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class IoTDBTtlIT {
+
+  private IoTDB daemon;
+
+  @Before
+  public void setUp() throws Exception {
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    EnvironmentUtils.closeStatMonitor();
+    daemon = IoTDB.getInstance();
+    daemon.active();
+    EnvironmentUtils.envSetUp();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    daemon.stop();
+    EnvironmentUtils.cleanEnv();
+  }
+
+  @Test
+  public void testTTL() throws SQLException {
+    try (IoTDBConnection connection = (IoTDBConnection) DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute("SET TTL TO root.TTL_SG1 1000");
+      } catch (SQLException e) {
+        assertEquals(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), e.getErrorCode());
+      }
+      try {
+        statement.execute("UNSET TTL TO root.TTL_SG1");
+      } catch (SQLException e) {
+        assertEquals(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), e.getErrorCode());
+      }
+
+      statement.execute("SET STORAGE GROUP TO root.TTL_SG1");
+      statement.execute("CREATE TIMESERIES root.TTL_SG1.s1 WITH DATATYPE=INT64,ENCODING=PLAIN");
+      try {
+        statement.execute("SET TTL TO root.TTL_SG1.s1 1000");
+      } catch (SQLException e) {
+        assertEquals(TSStatusCode.NOT_A_STORAGE_GROUP_ERROR.getStatusCode(), e.getErrorCode());
+      }
+
+      long now = System.currentTimeMillis();
+      for (int i = 0; i < 100; i++) {
+        statement.execute(String.format("INSERT INTO root.TTL_SG1(timestamp, s1) VALUES (%d, %d)",
+            now - 100 + i, i));
+      }
+      for (int i = 0; i < 100; i++) {
+        statement.execute(String.format("INSERT INTO root.TTL_SG1(timestamp, s1) VALUES (%d, %d)",
+            now - 100000 + i, i));
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.TTL_SG1")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+        assertEquals(200, cnt);
+      }
+
+      statement.execute("SET TTL TO root.TTL_SG1 10000");
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.TTL_SG1")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+        assertEquals(100, cnt);
+      }
+      for (int i = 0; i < 100; i++) {
+        boolean caught = false;
+        try {
+          statement.execute(String.format("INSERT INTO root.TTL_SG1(timestamp, s1) VALUES (%d, %d)",
+              now - 50000 + i, i));
+        } catch (SQLException e) {
+          if (TSStatusCode.OUT_OF_TTL_ERROR.getStatusCode() == e.getErrorCode()) {
+            caught = true;
+          }
+        }
+        assertTrue(caught);
+      }
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.TTL_SG1")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+        assertEquals(100, cnt);
+      }
+
+      statement.execute("UNSET TTL TO root.TTL_SG1");
+      for (int i = 0; i < 100; i++) {
+        statement.execute(String.format("INSERT INTO root.TTL_SG1(timestamp, s1) VALUES (%d, %d)",
+            now - 30000 + i, i));
+      }
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.TTL_SG1")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+        assertTrue(cnt >= 200);
+      }
+    }
+  }
+
+  @Test
+  public void testShowTTL() throws SQLException {
+    try (IoTDBConnection connection = (IoTDBConnection) DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.group1");
+      statement.execute("SET STORAGE GROUP TO root.group2");
+
+      String result = doQuery(statement, "SHOW ALL TTL", 2);
+      assertEquals("root.group2,null\n"
+          + "root.group1,null\n", result);
+      result = doQuery(statement, "SHOW TTL ON root.group1", 2);
+      assertEquals("root.group1,null\n", result);
+
+      statement.execute("SET TTL TO root.group1 10000");
+      result = doQuery(statement, "SHOW ALL TTL", 2);
+      assertEquals("root.group2,null\n"
+          + "root.group1,10000\n", result);
+      result = doQuery(statement, "SHOW TTL ON root.group1", 2);
+      assertEquals("root.group1,10000\n", result);
+
+      statement.execute("UNSET TTL TO root.group1");
+      result = doQuery(statement, "SHOW ALL TTL", 2);
+      assertEquals("root.group2,null\n"
+          + "root.group1,null\n", result);
+      result = doQuery(statement, "SHOW TTL ON root.group1", 2);
+      assertEquals("root.group1,null\n", result);
+    }
+  }
+
+  private String doQuery(Statement statement, String query, int columnSize) throws SQLException {
+    StringBuilder ret;
+    try (ResultSet resultSet = statement.executeQuery(query)) {
+      ret = new StringBuilder();
+      while (resultSet.next()) {
+        ret.append(resultSet.getString(2));
+        for (int i = 3; i <= columnSize + 1; i++) {
+          ret.append(",").append(resultSet.getString(i));
+        }
+        ret.append("\n");
+      }
+    }
+    return ret.toString();
+  }
+
+  @Test
+  public void testDefaultTTL() throws SQLException {
+    IoTDBDescriptor.getInstance().getConfig().setDefaultTTL(10000);
+    try (IoTDBConnection connection = (IoTDBConnection) DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      statement.execute("SET STORAGE GROUP TO root.group1");
+      statement.execute("SET STORAGE GROUP TO root.group2");
+
+      String result = doQuery(statement, "SHOW ALL TTL", 2);
+      assertEquals("root.group2,10000\n"
+          + "root.group1,10000\n", result);
+    } finally {
+      IoTDBDescriptor.getInstance().getConfig().setDefaultTTL(Long.MAX_VALUE);
+    }
+  }
+}
\ No newline at end of file
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBVersionIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBVersionIT.java
index b38dd23..11c5c5b 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBVersionIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBVersionIT.java
@@ -62,16 +62,9 @@ public class IoTDBVersionIT {
           + " WITH DATATYPE=INT32,ENCODING=PLAIN");
 
       // insert and flush enough times to make the version file persist
-      for (int i = 0; i < 2 * SimpleFileVersionController.getSaveInterval(); i ++) {
-        for (int j = 1; j <= 10; j ++) {
-          statement.execute(String
-              .format("INSERT INTO root.versionTest1(timestamp, s0) VALUES (%d, %d)", i*100+j, j));
-        }
-        statement.execute("FLUSH");
-        for (int j = 1; j <= 10; j ++) {
-          statement.execute(String
-              .format("INSERT INTO root.versionTest2(timestamp, s0) VALUES (%d, %d)", i*100+j, j));
-        }
+      for (int i = 0; i < SimpleFileVersionController.getSaveInterval() + 1; i ++) {
+        statement.execute(String
+            .format("INSERT INTO root.versionTest1(timestamp, s0) VALUES (%d, %d)", i*100, i));
         statement.execute("FLUSH");
         statement.execute("MERGE");
       }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
index 601257d..e34674d 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
@@ -22,14 +22,12 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.apache.iotdb.tsfile.exception.cache.CacheException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.junit.After;
 import org.junit.Assert;
@@ -77,7 +75,7 @@ public class MManagerAdvancedTest {
     try {
       // test file name
       List<String> fileNames = mmanager.getAllStorageGroupNames();
-      assertEquals(2, fileNames.size());
+      assertEquals(3, fileNames.size());
       if (fileNames.get(0).equals("root.vehicle.d0")) {
         assertEquals("root.vehicle.d1", fileNames.get(1));
       } else {
@@ -85,8 +83,8 @@ public class MManagerAdvancedTest {
       }
       // test filename by seriesPath
       assertEquals("root.vehicle.d0", mmanager.getStorageGroupNameByPath("root.vehicle.d0.s1"));
-      Map<String, ArrayList<String>> map = mmanager
-          .getAllPathGroupByFileName("root.vehicle.d1.*");
+      Map<String, List<String>> map = mmanager
+          .getAllPathGroupByStorageGroup("root.vehicle.d1.*");
       assertEquals(1, map.keySet().size());
       assertEquals(6, map.get("root.vehicle.d1").size());
       List<String> paths = mmanager.getPaths("root.vehicle.d0");
@@ -100,7 +98,7 @@ public class MManagerAdvancedTest {
   }
 
   @Test
-  public void testCache() throws PathErrorException, IOException, StorageGroupException, CacheException {
+  public void testCache() throws PathErrorException, IOException, StorageGroupException {
     mmanager.addPathToMTree("root.vehicle.d2.s0", "DOUBLE", "RLE");
     mmanager.addPathToMTree("root.vehicle.d2.s1", "BOOLEAN", "PLAIN");
     mmanager.addPathToMTree("root.vehicle.d2.s2.g0", "TEXT", "PLAIN");
@@ -111,19 +109,19 @@ public class MManagerAdvancedTest {
     Assert.assertEquals(TSDataType.INT64,
         mmanager.checkPathStorageGroupAndGetDataType("root.vehicle.d0.s1").getDataType());
 
-    Assert.assertEquals(false,
+    Assert.assertFalse(
         mmanager.checkPathStorageGroupAndGetDataType("root.vehicle.d0.s100").isSuccessfully());
-    Assert.assertEquals(null,
+    Assert.assertNull(
         mmanager.checkPathStorageGroupAndGetDataType("root.vehicle.d0.s100").getDataType());
 
-    MNode node = mmanager.getNodeByDeviceIdFromCache("root.vehicle.d0");
+    MNode node = mmanager.getNodeByPath("root.vehicle.d0");
     Assert.assertEquals(TSDataType.INT32, node.getChild("s0").getSchema().getType());
 
     try {
-      MNode node1 = mmanager.getNodeByDeviceIdFromCache("root.vehicle.d100");
+      mmanager.getNodeByPath("root.vehicle.d100");
       fail();
-    } catch (CacheException e) {
-
+    } catch (PathErrorException e) {
+      // ignore
     }
   }
 
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
index ad7a228..baa051a 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
@@ -137,7 +137,7 @@ public class MManagerBasicTest {
     }
 
     assertFalse(manager.pathExist("root.laptop.d2"));
-    assertFalse(manager.checkFileNameByPath("root.laptop.d2"));
+    assertFalse(manager.checkStorageGroupByPath("root.laptop.d2"));
 
     try {
       manager.deletePaths(Collections.singletonList(new Path("root.laptop.d1.s0")));
@@ -301,12 +301,12 @@ public class MManagerBasicTest {
       List<String> list = new ArrayList<>();
 
       list.add("root.laptop.d1");
-      assertEquals(list, manager.getAllFileNamesByPath("root.laptop.d1.s1"));
-      assertEquals(list, manager.getAllFileNamesByPath("root.laptop.d1"));
+      assertEquals(list, manager.getAllStorageGroupNamesByPath("root.laptop.d1.s1"));
+      assertEquals(list, manager.getAllStorageGroupNamesByPath("root.laptop.d1"));
 
       list.add("root.laptop.d2");
-      assertEquals(list, manager.getAllFileNamesByPath("root.laptop"));
-      assertEquals(list, manager.getAllFileNamesByPath("root"));
+      assertEquals(list, manager.getAllStorageGroupNamesByPath("root.laptop"));
+      assertEquals(list, manager.getAllStorageGroupNamesByPath("root"));
     } catch (MetadataErrorException | PathErrorException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -318,23 +318,23 @@ public class MManagerBasicTest {
     MManager manager = MManager.getInstance();
 
     try {
-      assertTrue(manager.getAllPathGroupByFileName("root").keySet().isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle.device").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle.device.sensor").isEmpty());
+      assertTrue(manager.getAllPathGroupByStorageGroup("root").keySet().isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle.device").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle.device.sensor").isEmpty());
 
       manager.setStorageGroupToMTree("root.vehicle");
-      assertFalse(manager.getAllFileNamesByPath("root.vehicle").isEmpty());
-      assertFalse(manager.getAllFileNamesByPath("root.vehicle.device").isEmpty());
-      assertFalse(manager.getAllFileNamesByPath("root.vehicle.device.sensor").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle1").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle1.device").isEmpty());
+      assertFalse(manager.getAllStorageGroupNamesByPath("root.vehicle").isEmpty());
+      assertFalse(manager.getAllStorageGroupNamesByPath("root.vehicle.device").isEmpty());
+      assertFalse(manager.getAllStorageGroupNamesByPath("root.vehicle.device.sensor").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle1").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle1.device").isEmpty());
 
       manager.setStorageGroupToMTree("root.vehicle1.device");
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle1.device1").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle1.device2").isEmpty());
-      assertTrue(manager.getAllFileNamesByPath("root.vehicle1.device3").isEmpty());
-      assertFalse(manager.getAllFileNamesByPath("root.vehicle1.device").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle1.device1").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle1.device2").isEmpty());
+      assertTrue(manager.getAllStorageGroupNamesByPath("root.vehicle1.device3").isEmpty());
+      assertFalse(manager.getAllStorageGroupNamesByPath("root.vehicle1.device").isEmpty());
     } catch (MetadataErrorException e) {
       e.printStackTrace();
       fail(e.getMessage());
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
index c0d6612..9e4eead 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
@@ -19,6 +19,8 @@
 package org.apache.iotdb.db.metadata;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -51,8 +53,7 @@ public class MManagerImproveTest {
 
     for (int j = 0; j < DEVICE_NUM; j++) {
       for (int i = 0; i < TIMESERIES_NUM; i++) {
-        String p = new StringBuilder().append("root.t1.v2.d").append(j).append(".s").append(i)
-            .toString();
+        String p = "root.t1.v2.d" + j + ".s" + i;
         mManager.addPathToMTree(p, "TEXT", "RLE");
       }
     }
@@ -68,9 +69,9 @@ public class MManagerImproveTest {
   public void checkSetUp() {
     mManager = MManager.getInstance();
 
-    assertEquals(true, mManager.pathExist("root.t1.v2.d3.s5"));
-    assertEquals(false, mManager.pathExist("root.t1.v2.d9.s" + TIMESERIES_NUM));
-    assertEquals(false, mManager.pathExist("root.t10"));
+    assertTrue(mManager.pathExist("root.t1.v2.d3.s5"));
+    assertFalse(mManager.pathExist("root.t1.v2.d9.s" + TIMESERIES_NUM));
+    assertFalse(mManager.pathExist("root.t10"));
   }
 
   @Test
@@ -94,7 +95,7 @@ public class MManagerImproveTest {
 
     startTime = System.currentTimeMillis();
     for (int i = 0; i < 100000; i++) {
-      assertEquals(true, mManager.pathExist(path));
+      assertTrue(mManager.pathExist(path));
     }
     endTime = System.currentTimeMillis();
     path_exist += endTime - startTime;
@@ -111,7 +112,7 @@ public class MManagerImproveTest {
 
     startTime = System.currentTimeMillis();
     for (int i = 0; i < 100000; i++) {
-      assertEquals(true, mManager.checkFileLevel(paths));
+      assertTrue(mManager.checkFileLevel(paths));
     }
     endTime = System.currentTimeMillis();
     check_filelevel += endTime - startTime;
@@ -131,32 +132,32 @@ public class MManagerImproveTest {
     logger.debug("get series type:\t" + get_seriestype);
   }
 
-  public void doOriginTest(String deviceId, List<String> measurementList)
+  private void doOriginTest(String deviceId, List<String> measurementList)
       throws PathErrorException, StorageGroupException {
     for (String measurement : measurementList) {
       String path = deviceId + "." + measurement;
-      assertEquals(true, mManager.pathExist(path));
+      assertTrue(mManager.pathExist(path));
       List<Path> paths = new ArrayList<>();
       paths.add(new Path(path));
-      assertEquals(true, mManager.checkFileLevel(paths));
+      assertTrue(mManager.checkFileLevel(paths));
       TSDataType dataType = mManager.getSeriesType(path);
       assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
-  public void doPathLoopOnceTest(String deviceId, List<String> measurementList)
+  private void doPathLoopOnceTest(String deviceId, List<String> measurementList)
       throws PathErrorException, StorageGroupException {
     for (String measurement : measurementList) {
       String path = deviceId + "." + measurement;
       List<Path> paths = new ArrayList<>();
       paths.add(new Path(path));
-      assertEquals(true, mManager.checkFileLevel(paths));
+      assertTrue(mManager.checkFileLevel(paths));
       TSDataType dataType = mManager.getSeriesTypeWithCheck(path);
       assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
-  public void doDealdeviceIdOnceTest(String deviceId, List<String> measurementList)
+  private void doDealdeviceIdOnceTest(String deviceId, List<String> measurementList)
       throws PathErrorException, StorageGroupException {
     boolean isFileLevelChecked;
     List<Path> tempList = new ArrayList<>();
@@ -169,30 +170,30 @@ public class MManagerImproveTest {
     MNode node = mManager.getNodeByPath(deviceId);
 
     for (String measurement : measurementList) {
-      assertEquals(true, mManager.pathExist(node, measurement));
+      assertTrue(mManager.pathExist(node, measurement));
       List<Path> paths = new ArrayList<>();
       paths.add(new Path(measurement));
       if (!isFileLevelChecked) {
         isFileLevelChecked = mManager.checkFileLevel(node, paths);
       }
-      assertEquals(true, isFileLevelChecked);
+      assertTrue(isFileLevelChecked);
       TSDataType dataType = mManager.getSeriesType(node, measurement);
       assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
-  public void doRemoveListTest(String deviceId, List<String> measurementList)
+  private void doRemoveListTest(String deviceId, List<String> measurementList)
       throws PathErrorException, StorageGroupException {
     for (String measurement : measurementList) {
       String path = deviceId + "." + measurement;
-      assertEquals(true, mManager.pathExist(path));
-      assertEquals(true, mManager.checkFileLevel(path));
+      assertTrue(mManager.pathExist(path));
+      assertTrue(mManager.checkFileLevel(path));
       TSDataType dataType = mManager.getSeriesType(path);
       assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
-  public void doAllImproveTest(String deviceId, List<String> measurementList)
+  private void doAllImproveTest(String deviceId, List<String> measurementList)
       throws PathErrorException, StorageGroupException {
     boolean isFileLevelChecked;
     try {
@@ -206,19 +207,19 @@ public class MManagerImproveTest {
       if (!isFileLevelChecked) {
         isFileLevelChecked = mManager.checkFileLevelWithCheck(node, measurement);
       }
-      assertEquals(true, isFileLevelChecked);
+      assertTrue(isFileLevelChecked);
       TSDataType dataType = mManager.getSeriesTypeWithCheck(node, measurement);
       assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
-  public void doCacheTest(String deviceId, List<String> measurementList)
+  private void doCacheTest(String deviceId, List<String> measurementList)
       throws CacheException, PathErrorException {
     MNode node = mManager.getNodeByDeviceIdFromCache(deviceId);
-    for (int i = 0; i < measurementList.size(); i++) {
-      assertEquals(true, node.hasChild(measurementList.get(i)));
-      MNode measurementNode = node.getChild(measurementList.get(i));
-      assertEquals(true, measurementNode.isLeaf());
+    for (String s : measurementList) {
+      assertTrue(node.hasChild(s));
+      MNode measurementNode = node.getChild(s);
+      assertTrue(measurementNode.isLeaf());
       TSDataType dataType = measurementNode.getSchema().getType();
       assertEquals(TSDataType.TEXT, dataType);
     }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
index 82e6150..465da84 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
@@ -24,11 +24,13 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
@@ -53,13 +55,15 @@ public class MTreeTest {
   public void testAddLeftNodePath() {
     MTree root = new MTree("root");
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1.b", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d1.s1.b", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       Assert.assertEquals(
           String.format("The Node [%s] is left node, the timeseries %s can't be created", "s1",
@@ -71,18 +75,20 @@ public class MTreeTest {
   public void testAddAndPathExist() {
     MTree root = new MTree("root");
     String path1 = "root";
-    assertEquals(true, root.isPathExist(path1));
-    assertEquals(false, root.isPathExist("root.laptop.d1"));
+    assertTrue(root.isPathExist(path1));
+    assertFalse(root.isPathExist("root.laptop.d1"));
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e1) {
       fail(e1.getMessage());
     }
-    assertEquals(true, root.isPathExist("root.laptop.d1"));
-    assertEquals(true, root.isPathExist("root.laptop"));
-    assertEquals(false, root.isPathExist("root.laptop.d1.s2"));
+    assertTrue(root.isPathExist("root.laptop.d1"));
+    assertTrue(root.isPathExist("root.laptop"));
+    assertFalse(root.isPathExist("root.laptop.d1.s2"));
     try {
-      root.addTimeseriesPath("aa.bb.cc", "INT32", "RLE");
+      root.addTimeseriesPath("aa.bb.cc", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       Assert.assertEquals(String.format("Timeseries %s is not right.", "aa.bb.cc"), e.getMessage());
     }
@@ -92,27 +98,32 @@ public class MTreeTest {
   public void testAddAndQueryPath() {
     MTree root = new MTree("root");
     try {
-      assertEquals(false, root.isPathExist("root.a.d0"));
-      assertEquals(false, root.checkFileNameByPath("root.a.d0"));
+      assertFalse(root.isPathExist("root.a.d0"));
+      assertFalse(root.checkFileNameByPath("root.a.d0"));
       root.setStorageGroup("root.a.d0");
-      root.addTimeseriesPath("root.a.d0.s0", "INT32", "RLE");
-      root.addTimeseriesPath("root.a.d0.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
-      assertEquals(false, root.isPathExist("root.a.d1"));
-      assertEquals(false, root.checkFileNameByPath("root.a.d1"));
+      assertFalse(root.isPathExist("root.a.d1"));
+      assertFalse(root.checkFileNameByPath("root.a.d1"));
       root.setStorageGroup("root.a.d1");
-      root.addTimeseriesPath("root.a.d1.s0", "INT32", "RLE");
-      root.addTimeseriesPath("root.a.d1.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.b.d0");
-      root.addTimeseriesPath("root.a.b.d0.s0", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
     } catch (PathErrorException | StorageGroupException e1) {
       e1.printStackTrace();
     }
 
     try {
-      HashMap<String, ArrayList<String>> result = root.getAllPath("root.a.*.s0");
+      Map<String, List<String>> result = root.getAllPath("root.a.*.s0");
       assertEquals(2, result.size());
       assertTrue(result.containsKey("root.a.d1"));
       assertEquals("root.a.d1.s0", result.get("root.a.d1").get(0));
@@ -137,32 +148,42 @@ public class MTreeTest {
     MTree root3 = new MTree("root");
     try {
       root.setStorageGroup("root.a.d0");
-      root.addTimeseriesPath("root.a.d0.s0", "INT32", "RLE");
-      root.addTimeseriesPath("root.a.d0.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.d1");
-      root.addTimeseriesPath("root.a.d1.s0", "INT32", "RLE");
-      root.addTimeseriesPath("root.a.d1.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.b.d0");
-      root.addTimeseriesPath("root.a.b.d0.s0", "INT32", "RLE");
+      root.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root1.setStorageGroup("root.a.d0");
-      root1.addTimeseriesPath("root.a.d0.s0", "INT32", "RLE");
-      root1.addTimeseriesPath("root.a.d0.s1", "INT32", "RLE");
+      root1.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root1.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root2.setStorageGroup("root.a.d1");
-      root2.addTimeseriesPath("root.a.d1.s0", "INT32", "RLE");
-      root2.addTimeseriesPath("root.a.d1.s1", "INT32", "RLE");
+      root2.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+      root2.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root3.setStorageGroup("root.a.b.d0");
-      root3.addTimeseriesPath("root.a.b.d0.s0", "INT32", "RLE");
-
-      String[] metadatas = new String[3];
-      metadatas[0] = root1.toString();
-      metadatas[1] = root2.toString();
-      metadatas[2] = root3.toString();
-      assertEquals(MTree.combineMetadataInStrings(metadatas), root.toString());
+      root3.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
+
+      String[] metadataStrs = new String[3];
+      metadataStrs[0] = root1.toString();
+      metadataStrs[1] = root2.toString();
+      metadataStrs[2] = root3.toString();
+      assertEquals(MTree.combineMetadataInStrings(metadataStrs), root.toString());
     } catch (PathErrorException | StorageGroupException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -175,11 +196,11 @@ public class MTreeTest {
     MTree root = new MTree("root");
     try {
       root.setStorageGroup("root.laptop.d1");
-      assertEquals(true, root.isPathExist("root.laptop.d1"));
-      assertEquals(true, root.checkFileNameByPath("root.laptop.d1"));
+      assertTrue(root.isPathExist("root.laptop.d1"));
+      assertTrue(root.checkFileNameByPath("root.laptop.d1"));
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1"));
-      assertEquals(false, root.isPathExist("root.laptop.d1.s1"));
-      assertEquals(true, root.checkFileNameByPath("root.laptop.d1.s1"));
+      assertFalse(root.isPathExist("root.laptop.d1.s1"));
+      assertTrue(root.checkFileNameByPath("root.laptop.d1.s1"));
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1.s1"));
     } catch (StorageGroupException e) {
       e.printStackTrace();
@@ -198,20 +219,24 @@ public class MTreeTest {
           e.getMessage());
     }
     // check timeseries
-    assertEquals(false, root.isPathExist("root.laptop.d1.s0"));
-    assertEquals(false, root.isPathExist("root.laptop.d1.s1"));
-    assertEquals(false, root.isPathExist("root.laptop.d2.s0"));
-    assertEquals(false, root.isPathExist("root.laptop.d2.s1"));
+    assertFalse(root.isPathExist("root.laptop.d1.s0"));
+    assertFalse(root.isPathExist("root.laptop.d1.s1"));
+    assertFalse(root.isPathExist("root.laptop.d2.s0"));
+    assertFalse(root.isPathExist("root.laptop.d2.s1"));
 
     try {
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1.s0"));
-      root.addTimeseriesPath("root.laptop.d1.s0", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1.s1"));
-      root.addTimeseriesPath("root.laptop.d1.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d2", root.getStorageGroupNameByPath("root.laptop.d2.s0"));
-      root.addTimeseriesPath("root.laptop.d2.s0", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d2.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d2", root.getStorageGroupNameByPath("root.laptop.d2.s1"));
-      root.addTimeseriesPath("root.laptop.d2.s1", "INT32", "RLE");
+      root.addTimeseriesPath("root.laptop.d2.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+          (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException | StorageGroupException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -222,18 +247,18 @@ public class MTreeTest {
       e.printStackTrace();
       fail(e.getMessage());
     }
-    assertEquals(false, root.isPathExist("root.laptop.d1.s0"));
+    assertFalse(root.isPathExist("root.laptop.d1.s0"));
     try {
       root.deletePath("root.laptop.d1");
     } catch (PathErrorException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
-    assertEquals(false, root.isPathExist("root.laptop.d1.s1"));
-    assertEquals(false, root.isPathExist("root.laptop.d1"));
-    assertEquals(true, root.isPathExist("root.laptop"));
-    assertEquals(true, root.isPathExist("root.laptop.d2"));
-    assertEquals(true, root.isPathExist("root.laptop.d2.s0"));
+    assertFalse(root.isPathExist("root.laptop.d1.s1"));
+    assertFalse(root.isPathExist("root.laptop.d1"));
+    assertTrue(root.isPathExist("root.laptop"));
+    assertTrue(root.isPathExist("root.laptop.d2"));
+    assertTrue(root.isPathExist("root.laptop.d2.s0"));
   }
 
   @Test
@@ -241,19 +266,19 @@ public class MTreeTest {
     // set storage group first
     MTree root = new MTree("root");
     try {
-      assertEquals(false, root.checkStorageGroup("root"));
-      assertEquals(false, root.checkStorageGroup("root1.laptop.d2"));
+      assertFalse(root.checkStorageGroup("root"));
+      assertFalse(root.checkStorageGroup("root1.laptop.d2"));
 
       root.setStorageGroup("root.laptop.d1");
-      assertEquals(true, root.checkStorageGroup("root.laptop.d1"));
-      assertEquals(false, root.checkStorageGroup("root.laptop.d2"));
-      assertEquals(false, root.checkStorageGroup("root.laptop"));
-      assertEquals(false, root.checkStorageGroup("root.laptop.d1.s1"));
+      assertTrue(root.checkStorageGroup("root.laptop.d1"));
+      assertFalse(root.checkStorageGroup("root.laptop.d2"));
+      assertFalse(root.checkStorageGroup("root.laptop"));
+      assertFalse(root.checkStorageGroup("root.laptop.d1.s1"));
 
       root.setStorageGroup("root.laptop.d2");
-      assertEquals(true, root.checkStorageGroup("root.laptop.d1"));
-      assertEquals(true, root.checkStorageGroup("root.laptop.d2"));
-      assertEquals(false, root.checkStorageGroup("root.laptop.d3"));
+      assertTrue(root.checkStorageGroup("root.laptop.d1"));
+      assertTrue(root.checkStorageGroup("root.laptop.d2"));
+      assertFalse(root.checkStorageGroup("root.laptop.d3"));
     } catch (StorageGroupException e) {
       e.printStackTrace();
       fail(e.getMessage());
diff --git a/server/src/test/java/org/apache/iotdb/db/query/control/FileReaderManagerTest.java b/server/src/test/java/org/apache/iotdb/db/query/control/FileReaderManagerTest.java
index 17dcb06..9d8f81b 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/control/FileReaderManagerTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/control/FileReaderManagerTest.java
@@ -72,8 +72,7 @@ public class FileReaderManagerTest {
 
         for (int i = 1; i <= 6; i++) {
           TsFileResource tsFile = tsFileResources[i];
-          testManager.addFilePathToMap(1L, tsFile,
-              false);
+          testManager.addFilePathToMap(1L, tsFile, false);
           manager.get(tsFile, false);
           Assert.assertTrue(manager.contains(tsFile, false));
         }
@@ -95,8 +94,7 @@ public class FileReaderManagerTest {
 
         for (int i = 4; i <= MAX_FILE_SIZE; i++) {
           TsFileResource tsFile = tsFileResources[i];
-          testManager.addFilePathToMap(2L, tsFile,
-              false);
+          testManager.addFilePathToMap(2L, tsFile, false);
           manager.get(tsFile, false);
           Assert.assertTrue(manager.contains(tsFile, false));
         }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/reader/ReaderTestHelper.java b/server/src/test/java/org/apache/iotdb/db/query/reader/ReaderTestHelper.java
index e771017..50e0c54 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/reader/ReaderTestHelper.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/reader/ReaderTestHelper.java
@@ -34,7 +34,7 @@ import org.junit.Before;
 
 public abstract class ReaderTestHelper {
 
-  protected String storageGroup = "storage_group1";
+  private String storageGroup = "storage_group1";
   protected String deviceId = "root.vehicle.d0";
   protected String measurementId = "s0";
   protected StorageGroupProcessor storageGroupProcessor;
diff --git a/server/src/test/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderTest.java b/server/src/test/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderTest.java
index a77e3af..f6346ca 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/reader/fileRelated/UnSealedTsFileReaderTest.java
@@ -39,7 +39,7 @@ public class UnSealedTsFileReaderTest extends ReaderTestHelper {
     QueryDataSource queryDataSource = storageGroupProcessor.query(deviceId, measurementId, context,
         null);
     TsFileResource resource = queryDataSource.getSeqResources().get(0);
-    Assert.assertEquals(false, resource.isClosed());
+    Assert.assertFalse(resource.isClosed());
     UnSealedTsFileIterateReader reader = new UnSealedTsFileIterateReader(resource, null, false);
     long time = 999;
     while (reader.hasNext()) {
@@ -58,7 +58,7 @@ public class UnSealedTsFileReaderTest extends ReaderTestHelper {
     QueryDataSource queryDataSource = storageGroupProcessor.query(deviceId, measurementId, context,
         null);
     TsFileResource resource = queryDataSource.getSeqResources().get(0);
-    Assert.assertEquals(false, resource.isClosed());
+    Assert.assertFalse(resource.isClosed());
     UnSealedTsFileReaderByTimestamp reader = new UnSealedTsFileReaderByTimestamp(
         resource);
 
@@ -74,13 +74,13 @@ public class UnSealedTsFileReaderTest extends ReaderTestHelper {
       Assert.assertEquals(time, value);
 
     }
-    Assert.assertEquals(true, reader.hasNext());
+    Assert.assertTrue(reader.hasNext());
 
     for (int time = 3050; time <= 3080; time += 10) {
       Integer value = (Integer) reader.getValueInTimestamp(time);
-      Assert.assertEquals(null, value);
+      Assert.assertNull(value);
     }
-    Assert.assertEquals(false, reader.hasNext());
+    Assert.assertFalse(reader.hasNext());
   }
 
 
diff --git a/server/src/test/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderTest.java b/server/src/test/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderTest.java
index 1e3941d..e6db5ef 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/reader/resourceRelated/UnseqResourceReaderTest.java
@@ -21,7 +21,6 @@ package org.apache.iotdb.db.query.reader.resourceRelated;
 
 import java.io.IOException;
 import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
-import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.reader.IPointReader;
@@ -112,7 +111,7 @@ public class UnseqResourceReaderTest extends ReaderTestHelper {
   }
 
   @Test
-  public void testUnseqResourceReaderByTimestamp() throws IOException, StorageEngineException {
+  public void testUnseqResourceReaderByTimestamp() throws IOException {
     Path path = new Path(deviceId, measurementId);
     QueryDataSource queryDataSource = storageGroupProcessor.query(deviceId, measurementId, context,
         null);
diff --git a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
index 44a4256..eee2800 100644
--- a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
+++ b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
@@ -32,6 +32,7 @@ import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.cache.DeviceMetaDataCache;
 import org.apache.iotdb.db.engine.cache.TsFileMetaDataCache;
 import org.apache.iotdb.db.engine.flush.FlushManager;
+import org.apache.iotdb.db.engine.merge.manage.MergeManager;
 import org.apache.iotdb.db.exception.StartupException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.metadata.MManager;
@@ -90,6 +91,9 @@ public class EnvironmentUtils {
     }
     // close metadata
     MManager.getInstance().clear();
+
+    MergeManager.getINSTANCE().stop();
+
     // delete all directory
     cleanAllDir();
 
@@ -159,6 +163,7 @@ public class EnvironmentUtils {
     StorageEngine.getInstance().reset();
     MultiFileLogNodeManager.getInstance().start();
     FlushManager.getInstance().start();
+    MergeManager.getINSTANCE().start();
     TEST_QUERY_JOB_ID = QueryResourceManager.getInstance().assignJobId();
     TEST_QUERY_CONTEXT = new QueryContext(TEST_QUERY_JOB_ID);
   }
diff --git a/server/src/test/java/org/apache/iotdb/db/writelog/recover/LogReplayerTest.java b/server/src/test/java/org/apache/iotdb/db/writelog/recover/LogReplayerTest.java
index ed147c3..fa9c6cf 100644
--- a/server/src/test/java/org/apache/iotdb/db/writelog/recover/LogReplayerTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/writelog/recover/LogReplayerTest.java
@@ -96,7 +96,7 @@ public class LogReplayerTest {
 
       for (int i = 0; i < 5; i++) {
         ReadOnlyMemChunk chunk = memTable.query("device" + i, "sensor" + i, TSDataType.INT64,
-            Collections.emptyMap());
+            Collections.emptyMap(), Long.MIN_VALUE);
         Iterator<TimeValuePair> iterator = chunk.getIterator();
         if (i == 0) {
           assertFalse(iterator.hasNext());
diff --git a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index 2df850b..3811736 100644
--- a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -27,10 +27,12 @@ public enum TSStatusCode {
   UNSUPPORTED_FETCH_METADATA_OPERATION_ERROR(302, "Unsupported fetch metadata operation"),
   FETCH_METADATA_ERROR(303, "Failed to fetch metadata"),
   CHECK_FILE_LEVEL_ERROR(304, "Meet error while checking file level"),
+  OUT_OF_TTL_ERROR(305, "timestamp falls out of TTL"),
   EXECUTE_STATEMENT_ERROR(400, "Execute statement error"),
   SQL_PARSE_ERROR(401, "Meet error while parsing SQL"),
   GENERATE_TIME_ZONE_ERROR(402, "Meet error while generating time zone"),
   SET_TIME_ZONE_ERROR(403, "Meet error while setting time zone"),
+  NOT_A_STORAGE_GROUP_ERROR(404, "Given path is not a storage group"),
   INTERNAL_SERVER_ERROR(500, "Internal server error"),
   WRONG_LOGIN_PASSWORD_ERROR(600,  "Username or password is wrong"),
   NOT_LOGIN_ERROR(601, "Has not logged in"),
@@ -40,7 +42,7 @@ public enum TSStatusCode {
   private int statusCode;
   private String statusMessage;
 
-  private TSStatusCode(int statusCode, String statusMessage) {
+  TSStatusCode(int statusCode, String statusMessage) {
     this.statusCode = statusCode;
     this.statusMessage = statusMessage;
   }