Add relational it (#13019)

* IoTDBFloatPrecisionIT

* modify it

* modify it

* fix it
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java
index f9ca418..d18b669 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java
@@ -413,11 +413,21 @@
     assertNonQueryTestFail(sql, errMsg, SessionConfig.DEFAULT_USER, SessionConfig.DEFAULT_PASSWORD);
   }
 
+  public static void assertTableNonQueryTestFail(String sql, String errMsg, String dbName) {
+    assertTableNonQueryTestFail(
+        sql, errMsg, SessionConfig.DEFAULT_USER, SessionConfig.DEFAULT_PASSWORD, dbName);
+  }
+
   public static void assertNonQueryTestFail(
       String sql, String errMsg, String userName, String password) {
     assertNonQueryTestFail(EnvFactory.getEnv(), sql, errMsg, userName, password);
   }
 
+  public static void assertTableNonQueryTestFail(
+      String sql, String errMsg, String userName, String password, String dbName) {
+    assertTableNonQueryTestFail(EnvFactory.getEnv(), sql, errMsg, userName, password, dbName);
+  }
+
   public static void assertNonQueryTestFail(
       BaseEnv env, String sql, String errMsg, String userName, String password) {
     try (Connection connection = env.getConnection(userName, password);
@@ -429,6 +439,18 @@
     }
   }
 
+  public static void assertTableNonQueryTestFail(
+      BaseEnv env, String sql, String errMsg, String userName, String password, String db) {
+    try (Connection connection = env.getConnection(userName, password, BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("use " + "\"" + db + "\"");
+      statement.execute(sql);
+      fail("No exception!");
+    } catch (SQLException e) {
+      Assert.assertTrue(e.getMessage(), e.getMessage().contains(errMsg));
+    }
+  }
+
   public static void assertResultSetEqual(
       ResultSet actualResultSet, String expectedHeader, String[] expectedRetArray) {
     assertResultSetEqual(
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java
new file mode 100644
index 0000000..cfe7d8c
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java
@@ -0,0 +1,106 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IOTDBInsertWithTimeAtAnyIndexIT {
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setAutoCreateSchemaEnabled(true);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testInsertTimeAtAnyIndex() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.addBatch("create database test");
+      statement.addBatch("use \"test\"");
+      statement.addBatch(
+          "create table (id1 string id, s1 int32 measurement, s2 int32 measurement)");
+      statement.addBatch("insert into db(id, s1, s2, time) ('d1', 2, 3, 1)");
+      statement.addBatch("insert into db(id, s1, time, s2) values ('d1', 20, 10, 30)");
+      statement.addBatch("insert into db(id, `time`, s1, s2) values ('d1', 100, 200, 300)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select time, s1 from db")) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getLong(1));
+        assertEquals(2, resultSet.getDouble(2), 0.00001);
+        assertTrue(resultSet.next());
+        assertEquals(10, resultSet.getLong(1));
+        assertEquals(20, resultSet.getDouble(2), 0.00001);
+        assertTrue(resultSet.next());
+        assertEquals(100, resultSet.getLong(1));
+        assertEquals(200, resultSet.getDouble(2), 0.00001);
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertMultiTime() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.addBatch("create database test");
+        statement.addBatch("use \"test\"");
+        statement.addBatch(
+            "create table (id1 string id, s1 int32 measurement, s2 int32 measurement)");
+        statement.addBatch("insert into db(id1, s1, s2, time, time) values ('d1', 2, 3, 1, 1)");
+        statement.executeBatch();
+        fail();
+      } catch (SQLException e) {
+        // expected
+      }
+
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBEncodingIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBEncodingIT.java
new file mode 100644
index 0000000..c6bc466
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBEncodingIT.java
@@ -0,0 +1,432 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.isession.ISession;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.apache.iotdb.itbase.env.BaseEnv.TABLE_SQL_DIALECT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class})
+@Ignore
+public class IoTDBEncodingIT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    try (ISession session = EnvFactory.getEnv().getSessionConnection(TABLE_SQL_DIALECT)) {
+      session.executeNonQueryStatement("CREATE DATABASE db1");
+    }
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    try (ISession session = EnvFactory.getEnv().getSessionConnection(TABLE_SQL_DIALECT)) {
+      session.executeNonQueryStatement("DROP DATABASE db1");
+    }
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderTS_2DIFF() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=TS_2DIFF");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(3,1300)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,1400)");
+
+      statement.execute("flush");
+
+      int[] result = new int[] {1100, 1200, 1300, 1400};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderTS_2DIFFOutofOrder() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=TS_2DIFF");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(7,1000)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,2200)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1200, 1100, 2200, 1000};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderRLE() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=RLE");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(3,1300)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,1400)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1100, 1200, 1300, 1400};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderRLEOutofOrder() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=RLE");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(7,1000)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,2200)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1200, 1100, 2200, 1000};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderGORILLA() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=GORILLA");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(3,1300)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,1400)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1100, 1200, 1300, 1400};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderGORILLAOutofOrder() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=GORILLA");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(7,1000)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,2200)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1200, 1100, 2200, 1000};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderZIGZAG() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=ZIGZAG");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(3,1300)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,1400)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1100, 1200, 1300, 1400};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderZIGZAGOutofOrder() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.salary WITH DATATYPE=INT64,ENCODING=ZIGZAG");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(1,1200)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(2,1100)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(7,1000)");
+      statement.execute("insert into root.db_0.tab0(time,salary) values(4,2200)");
+      statement.execute("flush");
+
+      int[] result = new int[] {1200, 1100, 2200, 1000};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          int salary = resultSet.getInt("root.db_0.tab0.salary");
+          assertEquals(result[index], salary);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderDictionary() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.city WITH DATATYPE=TEXT,ENCODING=DICTIONARY");
+      statement.execute("insert into root.db_0.tab0(time,city) values(1,\"Nanjing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(2,\"Nanjing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(3,\"Beijing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(4,\"Shanghai\")");
+      statement.execute("flush");
+
+      String[] result = new String[] {"Nanjing", "Nanjing", "Beijing", "Shanghai"};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          String city = resultSet.getString("root.db_0.tab0.city");
+          assertEquals(result[index], city);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testSetTimeEncoderRegularAndValueEncoderDictionaryOutOfOrder() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.db_0.tab0.city WITH DATATYPE=TEXT,ENCODING=DICTIONARY");
+      statement.execute("insert into root.db_0.tab0(time,city) values(1,\"Nanjing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(2,\"Nanjing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(4,\"Beijing\")");
+      statement.execute("insert into root.db_0.tab0(time,city) values(3,\"Shanghai\")");
+      statement.execute("flush");
+
+      String[] result = new String[] {"Nanjing", "Nanjing", "Shanghai", "Beijing"};
+      try (ResultSet resultSet = statement.executeQuery("select * from root.db_0.tab0")) {
+        int index = 0;
+        while (resultSet.next()) {
+          String city = resultSet.getString("root.db_0.tab0.city");
+          assertEquals(result[index], city);
+          index++;
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  public double SNR(int[] gd, int[] x, int length) {
+    double noise_power = 0, signal_power = 0;
+    for (int i = 0; i < length; i++) {
+      noise_power += (gd[i] - x[i]) * (gd[i] - x[i]);
+      signal_power += gd[i] * gd[i];
+    }
+    if (noise_power == 0) {
+      return Double.POSITIVE_INFINITY;
+    } else {
+      return 10 * Math.log10(signal_power / noise_power);
+    }
+  }
+
+  @Test
+  public void testDoublePrecision1() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.turbine1");
+      statement.execute(
+          "create timeseries root.turbine1.d1.s1 with datatype=DOUBLE, encoding=PLAIN, compression=SNAPPY");
+
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(1,1.2345678)");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.turbine1.**");
+
+      String str = "1.2345678";
+      while (resultSet.next()) {
+        assertEquals(str, resultSet.getString("root.turbine1.d1.s1"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testDoublePrecision2() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.turbine1");
+      statement.execute(
+          "create timeseries root.turbine1.d1.s1 with datatype=DOUBLE, encoding=RLE, compression=SNAPPY");
+
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(1,1.2345678)");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.turbine1.**");
+
+      String str = "1.23";
+      while (resultSet.next()) {
+        assertEquals(str, resultSet.getString("root.turbine1.d1.s1"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testFloatPrecision1() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.turbine1");
+      statement.execute(
+          "create timeseries root.turbine1.d1.s1 with datatype=FLOAT, encoding=PLAIN, compression=SNAPPY");
+
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(1,1.2345678)");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.turbine1.**");
+
+      String str = "1.2345678";
+      while (resultSet.next()) {
+        assertEquals(str, resultSet.getString("root.turbine1.d1.s1"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testFloatPrecision2() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.turbine1");
+      statement.execute(
+          "create timeseries root.turbine1.d1.s1 with datatype=FLOAT, encoding=RLE, compression=SNAPPY");
+
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(1,1.2345678)");
+
+      ResultSet resultSet = statement.executeQuery("select * from root.turbine1.**");
+
+      String str = "1.23";
+      while (resultSet.next()) {
+        assertEquals(str, resultSet.getString("root.turbine1.d1.s1"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBExecuteBatchIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBExecuteBatchIT.java
new file mode 100644
index 0000000..2727aa3
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBExecuteBatchIT.java
@@ -0,0 +1,149 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.RemoteIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.apache.iotdb.itbase.env.BaseEnv.TABLE_SQL_DIALECT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class, RemoteIT.class})
+@Ignore // 'Drop Table' and 'Alter table' is not supported
+public class IoTDBExecuteBatchIT {
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testJDBCExecuteBatch() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(5);
+      statement.addBatch("create database ln");
+      statement.addBatch("USE \"ln\"");
+      statement.addBatch("create table wf01 (id1 string id, temprature double measurement)");
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600000,1.2)");
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600001,2.3)");
+
+      statement.addBatch("drop table wf01");
+      statement.addBatch("create table wf01 (id1 string id, temprature double measurement)");
+
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600002,3.4)");
+      statement.executeBatch();
+      statement.clearBatch();
+      ResultSet resultSet = statement.executeQuery("select * from wf01");
+      int count = 0;
+
+      String[] timestamps = {"1509465600002"};
+      String[] values = {"3.4"};
+
+      while (resultSet.next()) {
+        assertEquals(timestamps[count], resultSet.getString("time"));
+        assertEquals(values[count], resultSet.getString("temperature"));
+        count++;
+      }
+    } catch (SQLException e) {
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testJDBCExecuteBatchForCreateMultiTimeSeriesPlan() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.setFetchSize(100);
+      statement.execute("create database ln");
+      statement.execute("USE \"ln\"");
+      statement.addBatch("create table wf01 (id1 string id, temprature double measurement)");
+
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600000,1.2)");
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600001,2.3)");
+      statement.addBatch("drop table wf01");
+
+      statement.addBatch(
+          "create table turbine (id1 string id, attr1 string attribute, attr2 string attribute, s1 boolean measurement, s2 float measurement)");
+
+      statement.addBatch("create table wf01 (id1 string id, temprature double measurement)");
+      statement.addBatch(
+          "insert into wf01(id1,time,temperature) values(\'wt01\', 1509465600002,3.4)");
+      statement.addBatch("alter table turbine add column s3 boolean measurement");
+      statement.executeBatch();
+      statement.clearBatch();
+      ResultSet resultSet = statement.executeQuery("select * from wf01");
+      String[] timestamps = {"1509465600002"};
+      String[] values = {"3.4"};
+      int count = 0;
+      while (resultSet.next()) {
+        assertEquals(timestamps[count], resultSet.getString("time"));
+        assertEquals(values[count], resultSet.getString("temperature"));
+        count++;
+      }
+      ResultSet timeSeriesResultSetForS1 = statement.executeQuery("describe turbine");
+      count = 0;
+      String[] keys = {"ColumnName", "DataType", "Category"};
+      String[][] value_columns = {
+        new String[] {"Time", "TIMESTAMP", "TIME"},
+        new String[] {"id1", "STRING", "ID"},
+        new String[] {"attr1", "STRING", "ATTRIBUTE"},
+        new String[] {"attr2", "STRING", "ATTRIBUTE"},
+        new String[] {"s1", "BOOLEAN", "MEASUREMENT"},
+        new String[] {"s2", "FLOAT", "MEASUREMENT"},
+      };
+
+      while (timeSeriesResultSetForS1.next()) {
+        for (int i = 0; i < keys.length; i++) {
+          assertEquals(value_columns[count][i], timeSeriesResultSetForS1.getString(keys[i]));
+        }
+        count++;
+      }
+    } catch (SQLException e) {
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFloatPrecisionIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFloatPrecisionIT.java
new file mode 100644
index 0000000..3dac960
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFloatPrecisionIT.java
@@ -0,0 +1,161 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.db.utils.MathUtils;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.RemoteIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+import static org.apache.iotdb.itbase.env.BaseEnv.TABLE_SQL_DIALECT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class, RemoteIT.class})
+public class IoTDBFloatPrecisionIT {
+
+  private static final String INSERT_TEMPLATE_SQL = "insert into %s(id1,time,%s) values(%s,%d,%s)";
+  private static List<String> sqls = new ArrayList<>();
+  private static final int TIMESTAMP = 10;
+  private static final String VALUE = "1.2345678901";
+  private static final float DELTA_FLOAT = 0.0000001f;
+  private static final double DELTA_DOUBLE = 0.0000001d;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    initCreateSQLStatement();
+
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void initCreateSQLStatement() {
+    sqls.add("CREATE DATABASE test");
+    StringJoiner createTableSql =
+        new StringJoiner(",", "CREATE TABLE vehicle (id1 string id, ", ")");
+    for (int i = 0; i < 10; i++) {
+      createTableSql.add("s" + i + "f" + " FLOAT measurement");
+      createTableSql.add("s" + i + "d" + " DOUBLE measurement");
+    }
+    sqls.add("USE \"test\"");
+    sqls.add(createTableSql.toString());
+    for (int i = 0; i < 10; i++) {
+      sqls.add(
+          String.format(INSERT_TEMPLATE_SQL, "vehicle", "s" + i + "f", "\'fd\'", TIMESTAMP, VALUE));
+      sqls.add(
+          String.format(INSERT_TEMPLATE_SQL, "vehicle", "s" + i + "d", "\'fd\'", TIMESTAMP, VALUE));
+    }
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  @Ignore
+  // CREATE TIMESERIES root.vehicle.%s.%s WITH DATATYPE=%s, ENCODING=%s, 'MAX_POINT_NUMBER'='%d'
+  // Should support 'MAX_POINT_NUMBER'='%d'
+  public void selectAllSQLTest() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("USE \"test\"");
+      int cnt;
+      try (ResultSet resultSet = statement.executeQuery("select * from vehicle")) {
+        assertNotNull(resultSet);
+        cnt = 0;
+        while (resultSet.next()) {
+          assertEquals(TIMESTAMP, resultSet.getTimestamp("time").getTime());
+          for (int i = 0; i < 10; i++) {
+            assertEquals(
+                MathUtils.roundWithGivenPrecision(Float.parseFloat(VALUE), i),
+                resultSet.getFloat("s" + i + "f"),
+                DELTA_FLOAT);
+            assertEquals(
+                MathUtils.roundWithGivenPrecision(Double.parseDouble(VALUE), i),
+                resultSet.getDouble("s" + i + "d"),
+                DELTA_DOUBLE);
+          }
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+
+      statement.execute("flush");
+      try (ResultSet resultSet = statement.executeQuery("select * from vehicle")) {
+        cnt = 0;
+        while (resultSet.next()) {
+          assertEquals(TIMESTAMP, resultSet.getTimestamp("time").getTime());
+          for (int i = 0; i < 10; i++) {
+            BigDecimal b = new BigDecimal(VALUE);
+            assertEquals(
+                b.setScale(i, RoundingMode.HALF_UP).floatValue(),
+                resultSet.getFloat("s" + i + "f"),
+                DELTA_FLOAT);
+            assertEquals(
+                b.setScale(i, RoundingMode.HALF_UP).doubleValue(),
+                resultSet.getDouble("s" + i + "d"),
+                DELTA_DOUBLE);
+          }
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFlushQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFlushQueryIT.java
new file mode 100644
index 0000000..42d1ce4
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBFlushQueryIT.java
@@ -0,0 +1,200 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Locale;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBFlushQueryIT {
+
+  private static String[] sqls =
+      new String[] {
+        "CREATE DATABASE test",
+        "USE \"test\"",
+        "CREATE TABLE vehicle (id1 string id, s0 int32 measurement)",
+        "insert into vehicle(id1,time,s0) values('d0',1,101)",
+        "insert into vehicle(id1,time,s0) values('d0',2,198)",
+        "insert into vehicle(id1,time,s0) values('d0',100,99)",
+        "insert into vehicle(id1,time,s0) values('d0',101,99)",
+        "insert into vehicle(id1,time,s0) values('d0',102,80)",
+        "insert into vehicle(id1,time,s0) values('d0',103,99)",
+        "insert into vehicle(id1,time,s0) values('d0',104,90)",
+        "insert into vehicle(id1,time,s0) values('d0',105,99)",
+        "insert into vehicle(id1,time,s0) values('d0',106,99)",
+        "flush",
+        "insert into vehicle(id1,time,s0) values('d0',2,10000)",
+        "insert into vehicle(id1,time,s0) values('d0',50,10000)",
+        "insert into vehicle(id1,time,s0) values('d0',1000,22222)",
+      };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        System.out.println(sql);
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      fail("insertData failed.");
+    }
+  }
+
+  @Test
+  public void selectAllSQLTest() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("USE \"test\"");
+      try (ResultSet resultSet = statement.executeQuery("SELECT * FROM vehicle"); ) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+      }
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testFlushGivenGroup() {
+    String insertTemplate =
+        "INSERT INTO vehicle(id1, time, s1, s2, s3) VALUES (%s, %d, %d, %f, %s)";
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("CREATE DATABASE group1");
+      statement.execute("CREATE DATABASE group2");
+      statement.execute("CREATE DATABASE group3");
+
+      for (int i = 1; i <= 3; i++) {
+        statement.execute(String.format("USE \"group%d\"", i));
+        statement.execute(
+            "CREATE TABLE vehicle (id1 string id, s1 int32 measurement, s2 float measurement, s3 string measurement)");
+        for (int j = 10; j < 20; j++) {
+          statement.execute(String.format(Locale.CHINA, insertTemplate, i, j, j, j * 0.1, j));
+        }
+      }
+      statement.execute("FLUSH");
+
+      for (int i = 1; i <= 3; i++) {
+        statement.execute(String.format("USE \"group%d\"", i));
+        for (int j = 0; j < 10; j++) {
+          statement.execute(String.format(Locale.CHINA, insertTemplate, i, j, j, j * 0.1, j));
+        }
+      }
+      statement.execute("FLUSH group1");
+      statement.execute("FLUSH group2,group3");
+
+      for (int i = 1; i <= 3; i++) {
+        statement.execute(String.format("USE \"group%d\"", i));
+        for (int j = 0; j < 30; j++) {
+          statement.execute(String.format(Locale.CHINA, insertTemplate, i, j, j, j * 0.1, j));
+        }
+      }
+      statement.execute("FLUSH group1 TRUE");
+      statement.execute("FLUSH group2,group3 FALSE");
+
+      for (int i = 1; i <= 3; i++) {
+        statement.execute(String.format("USE \"group%d\"", i));
+        int count = 0;
+        try (ResultSet resultSet = statement.executeQuery("SELECT * FROM vehicle")) {
+          while (resultSet.next()) {
+            count++;
+          }
+        }
+        assertEquals(30, count);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testFlushGivenGroupNoData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE nodatagroup1");
+      statement.execute("CREATE DATABASE nodatagroup2");
+      statement.execute("CREATE DATABASE nodatagroup3");
+      statement.execute("FLUSH nodatagroup1");
+      statement.execute("FLUSH nodatagroup2");
+      statement.execute("FLUSH nodatagroup3");
+      statement.execute("FLUSH nodatagroup1, nodatagroup2");
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  @Ignore
+  public void testFlushNotExistGroupNoData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.noexist.nodatagroup1");
+      try {
+        statement.execute(
+            "FLUSH root.noexist.nodatagroup1,root.notExistGroup1,root.notExistGroup2");
+      } catch (SQLException sqe) {
+        String expectedMsg =
+            "322: 322: storageGroup root.notExistGroup1,root.notExistGroup2 does not exist";
+        sqe.printStackTrace();
+        assertTrue(sqe.getMessage().contains(expectedMsg));
+      }
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiPartitionIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiPartitionIT.java
new file mode 100644
index 0000000..3d3654d
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiPartitionIT.java
@@ -0,0 +1,75 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.RemoteIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.Statement;
+
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class, RemoteIT.class})
+public class IoTDBInsertMultiPartitionIT {
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv()
+        .getConfig()
+        .getDataNodeCommonConfig()
+        .setWriteMemoryProportion("10000000:1");
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testInsertMultiPartition() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute("create table sg (id1 string id, s1 int32 measurement)");
+      statement.execute("insert into sg(id1,time,s1) values('d1',1,2)");
+      statement.execute("flush");
+      statement.execute("insert into sg(id1,time,s1) values('d1',2,2)");
+      statement.execute("insert into sg(id1,time,s1) values('d1',604800001,2)");
+      statement.execute("flush");
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiRowIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiRowIT.java
new file mode 100644
index 0000000..2509766
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertMultiRowIT.java
@@ -0,0 +1,195 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertMultiRowIT {
+  private static List<String> sqls = new ArrayList<>();
+  private static Connection connection;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setMaxInnerCompactionCandidateFileNum(2);
+    EnvFactory.getEnv().initClusterEnvironment();
+    initCreateSQLStatement();
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    close();
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void close() {
+    if (Objects.nonNull(connection)) {
+      try {
+        connection.close();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private static void initCreateSQLStatement() {
+    sqls.add("CREATE DATABASE t1");
+    sqls.add("USE \"t1\"");
+    sqls.add(
+        "create table wf01 (id1 string id, status boolean measurement, temperature float measurement)");
+  }
+
+  private static void insertData() throws ClassNotFoundException, SQLException {
+    connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+    Statement statement = connection.createStatement();
+
+    for (String sql : sqls) {
+      statement.execute(sql);
+    }
+
+    statement.close();
+  }
+
+  @Test
+  public void testInsertMultiRow() throws SQLException {
+    Statement st0 = connection.createStatement();
+    st0.execute("insert into wf01(id1, time, status) values ('wt01', 1, true)");
+    st0.execute("insert into wf01(id1, time, status) values ('wt01', 2, true), ('wt01', 3, false)");
+    st0.execute(
+        "insert into wf01(id1, time, status) values ('wt01', 4, true), ('wt01', 5, true), ('wt01', 6, false)");
+
+    st0.execute("insert into wf01(id1, time, temperature, status) values ('wt01', 7, 15.3, true)");
+    st0.execute(
+        "insert into wf01(id1, time, temperature, status) values ('wt01', 8, 18.3, false), ('wt01', 9, 23.1, false)");
+    st0.execute(
+        "insert into wf01(id1, time, temperature, status) values ('wt01', 10, 22.3, true), ('wt01', 11, 18.8, false), ('wt01', 12, 24.4, true)");
+    st0.close();
+
+    Statement st1 = connection.createStatement();
+    ResultSet rs1 = st1.executeQuery("select count(status) from wf01");
+    rs1.next();
+    long countStatus = rs1.getLong(1);
+    assertEquals(countStatus, 12L);
+
+    ResultSet rs2 = st1.executeQuery("select count(temperature) from wf01");
+    rs2.next();
+    long countTemperature = rs2.getLong(1);
+    assertEquals(countTemperature, 6L);
+
+    st1.close();
+  }
+
+  @Test(expected = Exception.class)
+  @Ignore
+  public void testInsertWithTimesColumns() throws SQLException {
+    Statement st1 = connection.createStatement();
+    st1.execute("insert into wf01(id1,time) values('wt01', 1)");
+  }
+
+  @Test
+  public void testInsertMultiRowWithMisMatchDataType() {
+    try {
+      Statement st1 = connection.createStatement();
+      st1.execute(
+          "insert into wf01(id1, time, status) values('wt01', 1, 1.0), ('wt01', 2, 'hello')");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(
+          e.getMessage().contains(Integer.toString(TSStatusCode.METADATA_ERROR.getStatusCode())));
+    }
+  }
+
+  @Test
+  @Ignore // TODO: delete
+  public void testInsertMultiRowWithNull() {
+    try (Statement st1 = connection.createStatement()) {
+      st1.execute(
+          "insert into root.t1.d99.wt01(time, s1, s2) values(100, null, 1), (101, null, 2)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(
+          e.getMessage().contains(Integer.toString(TSStatusCode.METADATA_ERROR.getStatusCode())));
+    }
+    try (Statement st2 = connection.createStatement()) {
+      st2.execute("CREATE TIMESERIES root.t1.d1.s1 WITH DATATYPE=double, ENCODING=PLAIN;");
+      st2.execute(
+          "INSERT INTO root.t1.d1(time, s1) VALUES (6, 10),(7,12),(8,14),(9,160),(10,null),(11,58)");
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testInsertMultiRowWithWrongTimestampPrecision() {
+    try (Statement st1 = connection.createStatement()) {
+      st1.execute(
+          "insert into wf01(id1, time, status) values('wt01', 1618283005586000, true), ('wt01', 1618283005586001, false)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(e.getMessage().contains("Current system timestamp precision is ms"));
+    }
+  }
+
+  @Test
+  public void testInsertMultiRowWithMultiTimePartition() throws Exception {
+    try (Statement st1 = connection.createStatement()) {
+      st1.execute("create table sg1 (id1 string id, s1 int32 measurement)");
+      st1.execute("insert into sg1(id1, time, s1) values('d1', 604800010,1)");
+      st1.execute("flush");
+      st1.execute("insert into sg1(id1, time, s1) values('d1', 604799990,1), ('d1', 604800001,1)");
+      st1.execute("flush");
+      ResultSet rs1 = st1.executeQuery("select time, s1 from sg1");
+      assertTrue(rs1.next());
+      assertEquals(604799990, rs1.getLong("time"));
+      assertTrue(rs1.next());
+      assertEquals(604800001, rs1.getLong("time"));
+      assertTrue(rs1.next());
+      assertEquals(604800010, rs1.getLong("time"));
+      assertFalse(rs1.next());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNaNIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNaNIT.java
new file mode 100644
index 0000000..bb597bf
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNaNIT.java
@@ -0,0 +1,199 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.RemoteIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.iotdb.db.utils.constant.TestConstant.TIMESTAMP_STR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ *
+ * <p>This test stores NaN Values and retrieves them via SQL Interface.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class, RemoteIT.class})
+public class IoTDBInsertNaNIT {
+
+  private static final String CREATE_TEMPLATE_SQL =
+      "CREATE TIMESERIES root.vehicle.%s.%s WITH DATATYPE=%s, ENCODING=%s, 'MAX_POINT_NUMBER'='%d'";
+  private static final String INSERT_TEMPLATE_SQL =
+      "insert into root.vehicle.%s(timestamp,%s) values(%d,%s)";
+  private static final String INSERT_BRAND_NEW_TEMPLATE_SQL =
+      "insert into root.cycle.%s(timestamp,%s) values(%d,%s)";
+  private static List<String> sqls = new ArrayList<>();
+  private static final int TIMESTAMP = 10;
+  private static final String VALUE = "NaN";
+  private static final float DELTA_FLOAT = 0.0000001f;
+  private static final double DELTA_DOUBLE = 0.0000001d;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    initCreateSQLStatement();
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void initCreateSQLStatement() {
+    sqls.add("CREATE DATABASE root.happy");
+    sqls.add("CREATE DATABASE root.cycle");
+    sqls.add("CREATE DATABASE root.vehicle.f0");
+    sqls.add("CREATE DATABASE root.vehicle.d0");
+    for (int i = 0; i < 10; i++) {
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "f0", "s" + i + "rle", "FLOAT", "RLE", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "f0", "s" + i + "2f", "FLOAT", "TS_2DIFF", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "d0", "s" + i + "rle", "DOUBLE", "RLE", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "d0", "s" + i + "2f", "DOUBLE", "TS_2DIFF", i));
+    }
+    for (int i = 0; i < 10; i++) {
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "f0", "s" + i + "rle", TIMESTAMP, VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "f0", "s" + i + "2f", TIMESTAMP, VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "d0", "s" + i + "rle", TIMESTAMP, VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "d0", "s" + i + "2f", TIMESTAMP, VALUE));
+    }
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void selectAllSQLTest() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      int cnt;
+      try (ResultSet resultSet = statement.executeQuery("select * from root.vehicle.*")) {
+        assertNotNull(resultSet);
+        cnt = 0;
+        while (resultSet.next()) {
+          assertEquals(TIMESTAMP + "", resultSet.getString(TIMESTAMP_STR));
+          for (int i = 0; i < 10; i++) {
+            assertEquals(
+                Float.parseFloat(VALUE),
+                resultSet.getFloat(String.format("root.vehicle.%s.%s", "f0", "s" + i + "rle")),
+                DELTA_FLOAT);
+            assertEquals(
+                Float.parseFloat(VALUE),
+                resultSet.getFloat(String.format("root.vehicle.%s.%s", "f0", "s" + i + "2f")),
+                DELTA_FLOAT);
+            assertEquals(
+                Double.parseDouble(VALUE),
+                resultSet.getDouble(String.format("root.vehicle.%s.%s", "d0", "s" + i + "rle")),
+                DELTA_DOUBLE);
+            assertEquals(
+                Double.parseDouble(VALUE),
+                resultSet.getDouble(String.format("root.vehicle.%s.%s", "d0", "s" + i + "2f")),
+                DELTA_DOUBLE);
+          }
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectTest() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE TIMESERIES root.happy.device1.sensor1.temperature WITH DATATYPE=DOUBLE, ENCODING=RLE");
+      statement.execute(
+          "INSERT INTO root.happy.device1.sensor1(timestamp,temperature) values(7925, NaN)");
+      int cnt;
+      try (ResultSet resultSet =
+          statement.executeQuery("select * from root.happy.device1.sensor1")) {
+        assertNotNull(resultSet);
+        cnt = 0;
+        while (resultSet.next()) {
+          assertEquals(7925 + "", resultSet.getString(TIMESTAMP_STR));
+          assertEquals(
+              Double.parseDouble(VALUE),
+              resultSet.getDouble("root.happy.device1.sensor1.temperature"),
+              DELTA_DOUBLE);
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testNaNValue() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format(INSERT_BRAND_NEW_TEMPLATE_SQL, "d0", "s0" + "2f", TIMESTAMP, VALUE));
+      boolean exist = false;
+      try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+        assertNotNull(resultSet);
+        while (resultSet.next()) {
+          if ((resultSet.getString(ColumnHeaderConstant.TIMESERIES)).contains("root.cycle.d0.s0")) {
+            exist = true;
+          }
+        }
+      }
+      assertTrue(exist);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNullIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNullIT.java
new file mode 100644
index 0000000..75c2a70
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertNullIT.java
@@ -0,0 +1,166 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.RemoteIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class, RemoteIT.class})
+public class IoTDBInsertNullIT {
+  private static final List<String> sqls = new ArrayList<>();
+  private static Connection connection;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    initCreateSQLStatement();
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    close();
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void close() {
+    if (Objects.nonNull(connection)) {
+      try {
+        connection.close();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private static void initCreateSQLStatement() {
+    sqls.add("CREATE DATABASE test");
+    sqls.add("USE \"test\"");
+    sqls.add(
+        "CREATE TABLE sg (id1 string id, s1 boolean measurement, s2 float measurement, s3 int32 measurement)");
+  }
+
+  private static void insertData() throws SQLException {
+    connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+    Statement statement = connection.createStatement();
+
+    for (String sql : sqls) {
+      statement.execute(sql);
+    }
+
+    statement.close();
+  }
+
+  @Test
+  public void testInsertNull() {
+    String[] retArray =
+        new String[] {
+          "1,d2,null,1.0,1,", "2,d2,true,null,2,", "3,d2,true,3.0,null,",
+        };
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("use \"test\"");
+      statement.execute("insert into sg(id1,time,s1,s2,s3) values('d2',1,null,1.0,1)");
+      statement.execute("insert into sg(id1,time,s1,s2,s3) values('d2',2,true,null,2)");
+      statement.execute("insert into sg(id1,time,s1,s2,s3) values('d2',3,true,3.0,null)");
+
+      try (ResultSet resultSet = statement.executeQuery("select * from sg")) {
+        assertNotNull(resultSet);
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "time,id1,s1,s2,s3",
+                new int[] {
+                  Types.TIMESTAMP, Types.VARCHAR, Types.BOOLEAN, Types.FLOAT, Types.INTEGER,
+                });
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            if (i == 1) {
+              actualBuilder.append(resultSet.getTimestamp(i).getTime()).append(",");
+            } else {
+              actualBuilder.append(resultSet.getString(i)).append(",");
+            }
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
+                .append(",");
+          }
+          assertEquals(expectedBuilder.toString(), actualBuilder.toString());
+          cnt++;
+        }
+        assertEquals(3, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private List<Integer> checkHeader(
+      ResultSetMetaData resultSetMetaData, String expectedHeaderStrings, int[] expectedTypes)
+      throws SQLException {
+    String[] expectedHeaders = expectedHeaderStrings.split(",");
+    Map<String, Integer> expectedHeaderToTypeIndexMap = new HashMap<>();
+    for (int i = 0; i < expectedHeaders.length; ++i) {
+      expectedHeaderToTypeIndexMap.put(expectedHeaders[i], i);
+    }
+
+    List<Integer> actualIndexToExpectedIndexList = new ArrayList<>();
+    for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+      Integer typeIndex = expectedHeaderToTypeIndexMap.get(resultSetMetaData.getColumnName(i));
+      assertNotNull(typeIndex);
+      assertEquals(expectedTypes[typeIndex], resultSetMetaData.getColumnType(i));
+      actualIndexToExpectedIndexList.add(typeIndex);
+    }
+    return actualIndexToExpectedIndexList;
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertWithoutTimeIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertWithoutTimeIT.java
new file mode 100644
index 0000000..2106626
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertWithoutTimeIT.java
@@ -0,0 +1,134 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.apache.iotdb.db.it.utils.TestUtils.assertTableNonQueryTestFail;
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertWithoutTimeIT {
+
+  private static final List<String> sqls =
+      Arrays.asList(
+          "CREATE DATABASE test",
+          "USE \"test\"",
+          "CREATE TABLE sg1(id1 string id, s1 int64 measurement, s2 float measurement, s3 string measurement)");
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    createTable();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private void createTable() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testInsertWithoutTime() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("use \"test\"");
+      statement.execute("insert into sg1(id1, s1, s2, s3) values ('d1',1, 1, '1')");
+      Thread.sleep(1);
+      statement.execute("insert into sg1(id1, s2, s1, s3) values ('d1',2, 2, '2')");
+      Thread.sleep(1);
+      statement.execute("insert into sg1(id1, s3, s2, s1) values ('d1','3', 3, 3)");
+      Thread.sleep(1);
+      statement.execute("insert into sg1(id1, s1) values ('d1',1)");
+      statement.execute("insert into sg1(id1, s2) values ('d1',2)");
+      statement.execute("insert into sg1(id1, s3) values ('d1','3')");
+    } catch (SQLException | InterruptedException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+
+    String expectedHeader = "count(s1),count(s2),count(s3),";
+    String[] retArray = new String[] {"4,4,4,"};
+    resultSetEqualTest("select count(s1), count(s2), count(s3) from sg1", expectedHeader, retArray);
+  }
+
+  @Test
+  @Ignore // TODO: delete
+  public void testInsertWithoutValueColumns() {
+    assertTableNonQueryTestFail(
+        "insert into sg1(id1, time) values ('d1', 1)",
+        "InsertStatement should contain at least one measurement",
+        "test");
+  }
+
+  @Test
+  public void testInsertMultiRow() {
+    assertTableNonQueryTestFail(
+        "insert into sg1(s3) values ('d1', '1'), ('d1', '2')",
+        "need timestamps when insert multi rows",
+        "test");
+    assertTableNonQueryTestFail(
+        "insert into sg1(id1, s1, s2) values ('d1', 1, 1), ('d1', 2, 2)",
+        "need timestamps when insert multi rows",
+        "test");
+  }
+
+  @Test
+  public void testInsertWithMultiTimesColumns() {
+    assertTableNonQueryTestFail(
+        "insert into sg1(id1, time, time) values ('d1', 1, 1)",
+        "One row should only have one time value",
+        "test");
+    assertTableNonQueryTestFail(
+        "insert into sg1(id1, time, s1, time) values ('d1', 1, 1, 1)",
+        "One row should only have one time value",
+        "test");
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiDeviceIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiDeviceIT.java
new file mode 100644
index 0000000..87e6587
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiDeviceIT.java
@@ -0,0 +1,359 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBMultiDeviceIT {
+
+  @Before
+  public void setUp() throws Exception {
+    // use small page
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setMaxNumberOfPointsInPage(100)
+        .setPageSizeInByte(1024 * 15)
+        .setGroupSizeInByte(1024 * 100)
+        .setMemtableSizeThreshold(1024 * 100)
+        .setPartitionInterval(100)
+        .setQueryThreadCount(2)
+        .setCompressor("LZ4");
+
+    EnvFactory.getEnv().initClusterEnvironment();
+
+    insertData();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : TestConstant.createSql) {
+        statement.addBatch(sql);
+      }
+
+      statement.addBatch("CREATE DATABASE test");
+      statement.addBatch("USE \"test\"");
+      statement.addBatch(
+          "create table t (id1 string id, id2 string id, s0 int32 measurement, s1 int32 measurement)");
+
+      // insert of data time range :0-100 into fans
+      for (int time = 0; time < 100; time++) {
+
+        String sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d2',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d3','%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d2',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+      }
+
+      // insert large amount of data time range : 1370 ~ 2400
+      for (int time = 1370; time < 2400; time++) {
+
+        String sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d2',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d3','%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d2',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+      }
+
+      // insert large amount of data time range : 300 ~ 1360
+      for (int time = 300; time < 1360; time++) {
+        // System.out.println("===" + time);
+        String sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d2',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d3','%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d2',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+      }
+
+      statement.addBatch("flush");
+
+      // unsequential data, memory data
+      for (int time = 1000; time < 1100; time++) {
+
+        String sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d2',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d3','%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d2',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+      }
+
+      // sequential data, memory data
+      for (int time = 20000; time < 20100; time++) {
+
+        String sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d2',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1,id2,time,s0) values('fans','d3','%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d0',%s,%s)", time, time % 7);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d1',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+        sql =
+            String.format(
+                "insert into t(id1, id2,time,s0) values('car','d2',%s,%s)", time, time % 4);
+        statement.addBatch(sql);
+      }
+      statement.executeBatch();
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testMultiDeviceQueryAndDelete() {
+    testSelectAll();
+    testSelectAfterDelete();
+  }
+
+  private void testSelectAll() {
+    String selectSql = "select * from t";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("use \"test\"");
+      Map<String, Long> lastTimeMap = new HashMap<>();
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          String id = resultSet.getString("id1") + "_" + resultSet.getString("id2");
+          long before = lastTimeMap.getOrDefault(id, -1L);
+          long cur = resultSet.getTimestamp("time").getTime();
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          lastTimeMap.put(id, cur);
+          cnt++;
+        }
+        assertEquals(13740, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private void testSelectAfterDelete() {
+    String selectSql = "select * from t";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("USE \"test\"");
+
+      statement.execute("DELETE FROM t WHERE id1='fans' and time <= 100");
+      statement.execute("DELETE FROM t WHERE id1='car' and time <= 100");
+      statement.execute("DELETE FROM t WHERE id1='fans' and time >= 20050 and time < 20100");
+      statement.execute("DELETE FROM t WHERE id1='car' and time >= 20050 and time < 20100");
+
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        long before = -1;
+        while (resultSet.next()) {
+          long cur = Long.parseLong(resultSet.getString("time"));
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          before = cur;
+          cnt++;
+        }
+        assertEquals(2140, cnt);
+      }
+
+      statement.execute("DELETE FROM t WHERE id1 = 'fans' and time <= 20000");
+      statement.execute("DELETE FROM t WHERE id1 = 'car' and time <= 20000");
+
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        long before = -1;
+        while (resultSet.next()) {
+          long cur = resultSet.getTimestamp("time").getTime();
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          before = cur;
+          cnt++;
+        }
+        assertEquals(49, cnt);
+      }
+
+      statement.execute("DELETE FROM t WHERE time >= 20000");
+
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        int cnt = 0;
+        long before = -1;
+        while (resultSet.next()) {
+          long cur = resultSet.getTimestamp("time").getTime();
+          if (cur <= before) {
+            fail("time order wrong!");
+          }
+          before = cur;
+          cnt++;
+        }
+        assertEquals(0, cnt);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBPartialInsertionIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBPartialInsertionIT.java
new file mode 100644
index 0000000..c3aa94c
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBPartialInsertionIT.java
@@ -0,0 +1,221 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.isession.ISession;
+import org.apache.iotdb.isession.SessionDataSet;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.RowRecord;
+import org.apache.tsfile.write.record.Tablet;
+import org.apache.tsfile.write.schema.IMeasurementSchema;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBPartialInsertionIT {
+  private final Logger logger = LoggerFactory.getLogger(IoTDBPartialInsertionIT.class);
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setAutoCreateSchemaEnabled(false);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testPartialInsertionAllFailed() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      try {
+        statement.execute("CREATE DATABASE test");
+        statement.execute("USE \"test\"");
+        statement.execute("create table sg1 (id1 string id, s0 int32 measurement)");
+        statement.execute("INSERT INTO sg1(id1, timestamp, s0) VALUES ('id', 1, 1)");
+        fail();
+      } catch (SQLException e) {
+        assertTrue(e.getMessage().contains("Path [root.sg1.s0] does not exist"));
+      }
+    }
+  }
+
+  @Test
+  public void testPartialInsertionRestart() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("CREATE DATABASE test");
+      statement.execute("USE \"test\"");
+      statement.execute(
+          "create table sg (id1 string id, s1 text measurement, s2 double measurement)");
+
+      try {
+        statement.execute("INSERT INTO sg(id1,time,s1,s2) VALUES('d1', 100,'test','test')");
+      } catch (SQLException e) {
+        // ignore
+      }
+    }
+
+    // TODO: replace restartDaemon() with new methods in Env.
+    /*
+    long time = 0;
+    try {
+      EnvironmentUtils.restartDaemon();
+      StorageEngine.getInstance().recover();
+      // wait for recover
+      while (!StorageEngine.getInstance().isAllSgReady()) {
+        Thread.sleep(500);
+        time += 500;
+        if (time > 10000) {
+          logger.warn("wait too long in restart, wait for: " + time / 1000 + "s");
+        }
+      }
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+     */
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("use \"test\"");
+
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM sg")) {
+        assertNotNull(resultSet);
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+          assertEquals("test", resultSet.getString("s1"));
+        }
+        assertEquals(1, cnt);
+      }
+      try (ResultSet resultSet = statement.executeQuery("SELECT s2 FROM sg")) {
+        assertNotNull(resultSet);
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testPartialInsertTablet() {
+    try (ISession session = EnvFactory.getEnv().getSessionConnection(BaseEnv.TABLE_SQL_DIALECT)) {
+      session.executeNonQueryStatement("create database test");
+      session.executeNonQueryStatement("use \"test\"");
+      session.executeNonQueryStatement(
+          "create table sg1 (id1 string id, s1 int64 measurement, s2 int64 measurement)");
+      List<IMeasurementSchema> schemaList = new ArrayList<>();
+      schemaList.add(new MeasurementSchema("id1", TSDataType.STRING));
+      schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
+      schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
+      schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
+      final List<Tablet.ColumnType> columnTypes =
+          Arrays.asList(
+              Tablet.ColumnType.ID,
+              Tablet.ColumnType.MEASUREMENT,
+              Tablet.ColumnType.MEASUREMENT,
+              Tablet.ColumnType.MEASUREMENT);
+      Tablet tablet = new Tablet("sg1", schemaList, columnTypes, 300);
+      long timestamp = 0;
+      for (long row = 0; row < 100; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, timestamp);
+        for (int s = 0; s < 4; s++) {
+          long value = timestamp;
+          if (s == 0) {
+            tablet.addValue(schemaList.get(s).getMeasurementId(), rowIndex, "d1");
+          } else {
+            tablet.addValue(schemaList.get(s).getMeasurementId(), rowIndex, value);
+          }
+        }
+        timestamp++;
+      }
+      timestamp = System.currentTimeMillis();
+      for (long row = 0; row < 100; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, timestamp);
+        for (int s = 0; s < 4; s++) {
+          long value = timestamp;
+          if (s == 0) {
+            tablet.addValue(schemaList.get(s).getMeasurementId(), rowIndex, "d1");
+          } else {
+            tablet.addValue(schemaList.get(s).getMeasurementId(), rowIndex, value);
+          }
+        }
+        timestamp++;
+      }
+      try {
+        session.insertRelationalTablet(tablet);
+      } catch (Exception e) {
+        if (!e.getMessage().contains("507")) {
+          fail(e.getMessage());
+        }
+      }
+      try (SessionDataSet dataSet = session.executeQueryStatement("SELECT * FROM sg1")) {
+        assertEquals(dataSet.getColumnNames().size(), 4);
+        assertEquals(dataSet.getColumnNames().get(0), "time");
+        assertEquals(dataSet.getColumnNames().get(1), "id1");
+        assertEquals(dataSet.getColumnNames().get(2), "s1");
+        assertEquals(dataSet.getColumnNames().get(3), "s2");
+        int cnt = 0;
+        while (dataSet.hasNext()) {
+          RowRecord rowRecord = dataSet.next();
+          long time = rowRecord.getFields().get(0).getLongV();
+          assertEquals(time, rowRecord.getFields().get(2).getLongV());
+          assertEquals(time, rowRecord.getFields().get(3).getLongV());
+          cnt++;
+        }
+        Assert.assertEquals(200, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverIT.java
new file mode 100644
index 0000000..881e9c0
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverIT.java
@@ -0,0 +1,307 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.cluster.env.AbstractEnv;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Locale;
+
+import static org.apache.iotdb.db.utils.constant.TestConstant.count;
+import static org.apache.iotdb.db.utils.constant.TestConstant.maxValue;
+import static org.apache.iotdb.db.utils.constant.TestConstant.minTime;
+import static org.apache.iotdb.db.utils.constant.TestConstant.minValue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBRecoverIT {
+
+  private static final Logger logger = LoggerFactory.getLogger(IoTDBRecoverIT.class);
+
+  private static final String TIMESTAMP_STR = "Time";
+  private static final String TEMPERATURE_STR = "temperature";
+  private static final String[] creationSqls =
+      new String[] {
+        "CREATE DATABASE test",
+        "USE \"test\"",
+        "CREATE TABLE vehicle (id1 string id, s0 int32 measurement, s1 int64 measurement, s2 float measurement, s3 text measurement, s4 boolean measurement)"
+      };
+  private static final String[] dataSet2 =
+      new String[] {
+        "CREATE DATABASE ln",
+        "USE \"ln\"",
+        "CREATE TABLE wf01 (id1 string id, status boolean measurement, temperature float measurement, hardware int32 measurement)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 1, 1.1, false, 11)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 2, 2.2, true, 22)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 3, 3.3, false, 33 )",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 4, 4.4, false, 44)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01',5, 5.5, false, 55)"
+      };
+  private final String d0s0 = "s0";
+  private final String d0s1 = "s1";
+  private final String d0s2 = "s2";
+  private final String d0s3 = "s3";
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    prepareData();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void recoverTest1() {
+    // stop cluster
+    EnvFactory.getEnv().shutdownAllDataNodes();
+    logger.info("All DataNodes are shut down");
+    EnvFactory.getEnv().shutdownAllConfigNodes();
+    logger.info("All ConfigNodes are shut down");
+    EnvFactory.getEnv().startAllConfigNodes();
+    logger.info("All ConfigNodes are started");
+    EnvFactory.getEnv().startAllDataNodes();
+    logger.info("All DataNodes are started");
+    // check cluster whether restart
+    ((AbstractEnv) EnvFactory.getEnv()).checkClusterStatusWithoutUnknown();
+    String[] retArray = new String[] {"0,2", "0,4", "0,3"};
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("use \"ln\"");
+      String selectSql = "select count(temperature) from wf01 where time > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(count(TEMPERATURE_STR));
+        Assert.assertEquals(retArray[0], ans);
+      }
+
+      selectSql = "select min_time(temperature) from wf01 where time > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(minTime(TEMPERATURE_STR));
+        Assert.assertEquals(retArray[1], ans);
+      }
+
+      selectSql = "select min_time(temperature) from wf01 where temperature > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(minTime(TEMPERATURE_STR));
+        Assert.assertEquals(retArray[2], ans);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+
+    // max min ValueTest
+    retArray = new String[] {"0,8499,500.0", "0,2499,500.0"};
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      String selectSql =
+          "select max_value(s0),min_value(s2) "
+              + "from root.vehicle.d0 where time >= 100 and time < 9000";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time")
+                + ","
+                + resultSet.getString(maxValue(d0s0))
+                + ","
+                + resultSet.getString(minValue(d0s2));
+        Assert.assertEquals(retArray[0], ans);
+      }
+
+      selectSql = "select max_value(s0),min_value(s2) from root.vehicle.d0 where time < 2500";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time")
+                + ","
+                + resultSet.getString(maxValue(d0s0))
+                + ","
+                + resultSet.getString(minValue(d0s2));
+        Assert.assertEquals(retArray[1], ans);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void recoverTest2() {
+    // stop cluster
+    EnvFactory.getEnv().shutdownAllDataNodes();
+    logger.info("All DataNodes are shut down");
+    EnvFactory.getEnv().shutdownAllConfigNodes();
+    logger.info("All ConfigNodes are shut down");
+    EnvFactory.getEnv().startAllConfigNodes();
+    logger.info("All ConfigNodes are started");
+    EnvFactory.getEnv().startAllDataNodes();
+    logger.info("All DataNodes are started");
+    // wait for cluster to start and check
+    ((AbstractEnv) EnvFactory.getEnv()).checkClusterStatusWithoutUnknown();
+    // count test
+    String[] retArray = new String[] {"0,2001,2001,2001,2001", "0,7500,7500,7500,7500"};
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      String selectSql =
+          "select count(s0),count(s1),count(s2),count(s3) "
+              + "from vehicle where time >= 6000 and time <= 9000";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time")
+                + ","
+                + resultSet.getString(count(d0s0))
+                + ","
+                + resultSet.getString(count(d0s1))
+                + ","
+                + resultSet.getString(count(d0s2))
+                + ","
+                + resultSet.getString(count(d0s3));
+        Assert.assertEquals(retArray[0], ans);
+      }
+
+      selectSql = "select count(s0),count(s1),count(s2),count(s3) from vehicle";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time")
+                + ","
+                + resultSet.getString(count(d0s0))
+                + ","
+                + resultSet.getString(count(d0s1))
+                + ","
+                + resultSet.getString(count(d0s2))
+                + ","
+                + resultSet.getString(count(d0s3));
+        Assert.assertEquals(retArray[1], ans);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private void prepareData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : creationSqls) {
+        statement.execute(sql);
+      }
+
+      for (String sql : dataSet2) {
+        statement.execute(sql);
+      }
+
+      // prepare BufferWrite file
+      String insertTemplate =
+          "INSERT INTO vehicle(id1,timestamp,s0,s1,s2,s3,s4)" + " VALUES('d0',%d,%d,%d,%f,%s,%s)";
+      for (int i = 5000; i < 7000; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+      for (int i = 7500; i < 8500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+      // prepare Unseq-File
+      for (int i = 500; i < 1500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+      for (int i = 3000; i < 6500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+
+      // prepare BufferWrite cache
+      for (int i = 9000; i < 10000; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.executeBatch();
+      // prepare Overflow cache
+      for (int i = 2000; i < 2500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverUnclosedIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverUnclosedIT.java
new file mode 100644
index 0000000..29f4e5b
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRecoverUnclosedIT.java
@@ -0,0 +1,257 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.cluster.env.AbstractEnv;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Locale;
+
+import static org.apache.iotdb.db.utils.constant.TestConstant.count;
+import static org.apache.iotdb.db.utils.constant.TestConstant.maxValue;
+import static org.apache.iotdb.db.utils.constant.TestConstant.minTime;
+import static org.apache.iotdb.db.utils.constant.TestConstant.minValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBRecoverUnclosedIT {
+  private static final Logger logger = LoggerFactory.getLogger(IoTDBRecoverUnclosedIT.class);
+  private static final String TIMESTAMP_STR = "time";
+  private static final String TEMPERATURE_STR = "temperature";
+  private static final String[] creationSqls =
+      new String[] {
+        "CREATE DATABASE test",
+        "USE \"test\"",
+        "CREATE TABLE vehicle (id1 string id, s0 int32 measurement, s1 int64 measurement, s2 float measurement, s3 text measurement, s4 boolean measurement)"
+      };
+  private static final String[] dataSet2 =
+      new String[] {
+        "CREATE DATABASE ln",
+        "USE \"ln\"",
+        "CREATE TABLE wf01 (id1 string id, status boolean measurement, temperature float measurement, hardware int32 measurement)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 1, 1.1, false, 11)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 2, 2.2, true, 22)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 3, 3.3, false, 33 )",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01', 4, 4.4, false, 44)",
+        "INSERT INTO wf01(id1, time,temperature,status, hardware) "
+            + "values('wt01',5, 5.5, false, 55)"
+      };
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setWalMode("SYNC");
+    EnvFactory.getEnv().initClusterEnvironment();
+    prepareData();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void test() throws SQLException, IOException {
+    String[] retArray = new String[] {"0,2", "0,4", "0,3"};
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("use \"ln\"");
+      String selectSql = "select count(temperature) from wf01 where time > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(count(TEMPERATURE_STR));
+        assertEquals(retArray[0], ans);
+      }
+
+      selectSql = "select min_time(temperature) from wf01 where time > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(minTime(TEMPERATURE_STR));
+        assertEquals(retArray[1], ans);
+      }
+
+      selectSql = "select min_time(temperature) from wf01 where temperature > 3";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time") + "," + resultSet.getString(minTime(TEMPERATURE_STR));
+        assertEquals(retArray[2], ans);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+
+    insertMoreData();
+
+    // stop cluster
+    EnvFactory.getEnv().shutdownAllDataNodes();
+    logger.info("All DataNodes are shut down");
+    EnvFactory.getEnv().shutdownAllConfigNodes();
+    logger.info("All ConfigNodes are shut down");
+    EnvFactory.getEnv().startAllConfigNodes();
+    logger.info("All ConfigNodes are started");
+    EnvFactory.getEnv().startAllDataNodes();
+    logger.info("All DataNodes are started");
+    // wait for cluster to start and check
+    ((AbstractEnv) EnvFactory.getEnv()).checkClusterStatusWithoutUnknown();
+
+    // test count,
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String selectSql = "select count(*) from vehicle";
+      ResultSet tempResultSet = statement.executeQuery(selectSql);
+      assertNotNull(tempResultSet);
+      tempResultSet.next();
+      String d0s0 = "s0";
+      String d0s1 = "s1";
+      String d0s2 = "s2";
+      assertEquals(7500, tempResultSet.getInt("count(" + d0s0 + ")"));
+
+      // test max, min value
+      retArray = new String[] {"0,8499,500.0", "0,2499,500.0"};
+      selectSql =
+          "select max_value(s0),min_value(s2) " + "from vehicle where time >= 100 and time < 9000";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString(TIMESTAMP_STR)
+                + ","
+                + resultSet.getString(maxValue(d0s0))
+                + ","
+                + resultSet.getString(minValue(d0s2));
+        assertEquals(retArray[0], ans);
+      }
+
+      selectSql = "select max_value(s1),min_value(s2) from vehicle where time < 2500";
+      try (ResultSet resultSet = statement.executeQuery(selectSql)) {
+        assertNotNull(resultSet);
+        resultSet.next();
+        String ans =
+            resultSet.getString("time")
+                + ","
+                + resultSet.getString(maxValue(d0s1))
+                + ","
+                + resultSet.getString(minValue(d0s2));
+        assertEquals(retArray[1], ans);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private void prepareData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      for (String sql : creationSqls) {
+        statement.execute(sql);
+      }
+
+      for (String sql : dataSet2) {
+        statement.execute(sql);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private void insertMoreData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      // prepare BufferWrite file
+      String insertTemplate =
+          "INSERT INTO vehicle(id1,timestamp,s0,s1,s2,s3,s4)" + " VALUES('d0',%d,%d,%d,%f,%s,%s)";
+      for (int i = 5000; i < 7000; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.executeBatch();
+      for (int i = 7500; i < 8500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+      // prepare Unseq-File
+      for (int i = 500; i < 1500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      for (int i = 3000; i < 6500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+      // prepare BufferWrite cache
+      for (int i = 9000; i < 10000; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.executeBatch();
+      // prepare Overflow cache
+      for (int i = 2000; i < 2500; i++) {
+        statement.addBatch(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.executeBatch();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRestartIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRestartIT.java
new file mode 100644
index 0000000..f17f80e
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBRestartIT.java
@@ -0,0 +1,388 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.db.conf.IoTDBConfig;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.apache.iotdb.db.utils.constant.TestConstant.TIMESTAMP_STR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+@Ignore
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBRestartIT {
+
+  private final Logger logger = LoggerFactory.getLogger(IoTDBRestartIT.class);
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testRestart() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute("create table turbine (id1 string id, s1 float measurement)");
+      statement.execute("insert into turbine(id1, timestamp,s1) values('d1', 1,1.0)");
+      statement.execute("flush");
+    }
+
+    try {
+      // TODO: replace restartDaemon() with new methods in Env.
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into turbine(id1, timestamp,s1) values('d1', 2,1.0)");
+    }
+
+    try {
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into turbine(id1, timestamp,s1) values('d1', 3,1.0)");
+
+      String[] exp = new String[] {"1,1.0", "2,1.0", "3,1.0"};
+      int cnt = 0;
+      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM turbine")) {
+        assertNotNull(resultSet);
+        while (resultSet.next()) {
+          String result = resultSet.getString("time") + "," + resultSet.getString(2);
+          assertEquals(exp[cnt], result);
+          cnt++;
+        }
+      }
+    }
+  }
+
+  @Test
+  public void testRestartDelete() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(1,1)");
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(2,2)");
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(3,3)");
+    }
+
+    long time = 0;
+    /*
+    try {
+      EnvironmentUtils.restartDaemon();
+      StorageEngine.getInstance().recover();
+      // wait for recover
+      while (!StorageEngine.getInstance().isAllSgReady()) {
+        Thread.sleep(500);
+        time += 500;
+        if (time > 10000) {
+          logger.warn("wait too long in restart, wait for: " + time / 1000 + "s");
+        }
+      }
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+     */
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("delete from root.turbine.d1.s1 where time<=1");
+
+      ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.turbine.d1");
+      assertNotNull(resultSet);
+      String[] exp = new String[] {"2,2.0", "3,3.0"};
+      int cnt = 0;
+      try {
+        while (resultSet.next()) {
+          String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+          assertEquals(exp[cnt], result);
+          cnt++;
+        }
+
+        statement.execute("flush");
+        statement.execute("delete from root.turbine.d1.s1 where time<=2");
+
+        exp = new String[] {"3,3.0"};
+        resultSet = statement.executeQuery("SELECT s1 FROM root.turbine.d1");
+        assertNotNull(resultSet);
+        cnt = 0;
+        while (resultSet.next()) {
+          String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+          assertEquals(exp[cnt], result);
+          cnt++;
+        }
+      } finally {
+        resultSet.close();
+      }
+    }
+  }
+
+  @Test
+  public void testRestartQueryLargerThanEndTime() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(1,1)");
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(2,2)");
+    }
+
+    try {
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(3,1)");
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(4,2)");
+    }
+
+    try {
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      String[] exp =
+          new String[] {
+            "4,2.0",
+          };
+      int cnt = 0;
+      try (ResultSet resultSet =
+          statement.executeQuery("SELECT s1 FROM root.turbine.d1 where time > 3")) {
+        assertNotNull(resultSet);
+        while (resultSet.next()) {
+          String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+          assertEquals(exp[cnt], result);
+          cnt++;
+        }
+      }
+      assertEquals(1, cnt);
+    }
+  }
+
+  @Test
+  public void testRestartEndTime() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(1,1)");
+      statement.execute("insert into root.turbine.d1(timestamp,s1) values(2,2)");
+    }
+
+    try {
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine.d1(timestamp,s2) values(1,1)");
+      statement.execute("insert into root.turbine.d1(timestamp,s2) values(2,2)");
+    }
+
+    try {
+      // EnvironmentUtils.restartDaemon();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      String[] exp = new String[] {"1,1.0", "2,2.0"};
+      int cnt = 0;
+      try (ResultSet resultSet = statement.executeQuery("SELECT s2 FROM root.turbine.d1")) {
+        assertNotNull(resultSet);
+        while (resultSet.next()) {
+          String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+          assertEquals(exp[cnt], result);
+          cnt++;
+        }
+      }
+      assertEquals(2, cnt);
+    }
+  }
+
+  @Test
+  public void testRecoverWALMismatchDataType() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine1.d1(timestamp,s1,s2) values(1,1.1,2.2)");
+      statement.execute("delete timeseries root.turbine1.d1.s1");
+      statement.execute(
+          "create timeseries root.turbine1.d1.s1 with datatype=INT32, encoding=RLE, compression=SNAPPY");
+    }
+
+    // EnvironmentUtils.restartDaemon();
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      try (ResultSet resultSet = statement.executeQuery("select * from root.**")) {
+        assertNotNull(resultSet);
+        int cnt = 0;
+        assertEquals(3, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          assertEquals("1", resultSet.getString(1));
+          assertNull(resultSet.getString(2));
+          assertEquals("2.2", resultSet.getString(3));
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    }
+  }
+
+  @Test
+  public void testRecoverWALDeleteSchema() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine1.d1(timestamp,s1,s2) values(1,1.1,2.2)");
+      statement.execute("delete timeseries root.turbine1.d1.s1");
+    }
+
+    // EnvironmentUtils.restartDaemon();
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      try (ResultSet resultSet = statement.executeQuery("select * from root.**")) {
+        assertNotNull(resultSet);
+        int cnt = 0;
+        assertEquals(2, resultSet.getMetaData().getColumnCount());
+        while (resultSet.next()) {
+          assertEquals("1", resultSet.getString(1));
+          assertEquals("2.2", resultSet.getString(2));
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    }
+  }
+
+  @Test
+  public void testRecoverWALDeleteSchemaCheckResourceTime() throws Exception {
+    IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+    int avgSeriesPointNumberThreshold = config.getAvgSeriesPointNumberThreshold();
+    config.setAvgSeriesPointNumberThreshold(2);
+    long tsFileSize = config.getSeqTsFileSize();
+    long unFsFileSize = config.getSeqTsFileSize();
+    config.setSeqTsFileSize(10000000);
+    config.setUnSeqTsFileSize(10000000);
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("create timeseries root.turbine1.d1.s1 with datatype=INT64");
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(1,1)");
+      statement.execute("insert into root.turbine1.d1(timestamp,s1) values(2,1)");
+      statement.execute("create timeseries root.turbine1.d1.s2 with datatype=BOOLEAN");
+      statement.execute("insert into root.turbine1.d1(timestamp,s2) values(3,true)");
+      statement.execute("insert into root.turbine1.d1(timestamp,s2) values(4,true)");
+    }
+
+    Thread.sleep(1000);
+    // EnvironmentUtils.restartDaemon();
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      long[] result = new long[] {1L, 2L};
+      ResultSet resultSet =
+          statement.executeQuery("select s1 from root.turbine1.d1 where time < 3");
+      assertNotNull(resultSet);
+      int cnt = 0;
+      while (resultSet.next()) {
+        assertEquals(resultSet.getLong(1), result[cnt]);
+        cnt++;
+      }
+      assertEquals(2, cnt);
+    }
+
+    config.setAvgSeriesPointNumberThreshold(avgSeriesPointNumberThreshold);
+    config.setSeqTsFileSize(tsFileSize);
+    config.setUnSeqTsFileSize(unFsFileSize);
+  }
+
+  @Test
+  public void testRecoverFromFlushMemTableError() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.turbine1.d1(timestamp,s1,s2) values(1,1.1,2.2)");
+    }
+
+    // mock exception during flush memtable
+    // EnvironmentUtils.restartDaemon();
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      try (ResultSet resultSet = statement.executeQuery("select * from root.**")) {
+        assertNotNull(resultSet);
+        int cnt = 0;
+        while (resultSet.next()) {
+          assertEquals("1", resultSet.getString(1));
+          assertEquals("1.1", resultSet.getString(2));
+          assertEquals("2.2", resultSet.getString(3));
+          cnt++;
+        }
+        assertEquals(1, cnt);
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBSameMeasurementsDifferentTypesIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBSameMeasurementsDifferentTypesIT.java
new file mode 100644
index 0000000..2197155
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBSameMeasurementsDifferentTypesIT.java
@@ -0,0 +1,158 @@
+/*
+ * 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.relational.it.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+@Ignore
+// TODO: Delete this IT
+public class IoTDBSameMeasurementsDifferentTypesIT {
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    // use small page
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setMaxNumberOfPointsInPage(1000)
+        .setPageSizeInByte(1024 * 150)
+        .setGroupSizeInByte(1024 * 1000)
+        .setMemtableSizeThreshold(1024 * 1000);
+
+    EnvFactory.getEnv().initClusterEnvironment();
+
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void insertData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+
+      statement.execute("CREATE DATABASE root.fans");
+      statement.execute("CREATE TIMESERIES root.fans.d0.s0 WITH DATATYPE=INT32, ENCODING=RLE");
+      statement.execute("CREATE TIMESERIES root.fans.d1.s0 WITH DATATYPE=INT64, ENCODING=RLE");
+
+      for (int time = 1; time < 10; time++) {
+
+        String sql =
+            String.format("insert into root.fans.d0(timestamp,s0) values(%s,%s)", time, time % 10);
+        statement.execute(sql);
+        sql = String.format("insert into root.fans.d1(timestamp,s0) values(%s,%s)", time, time % 5);
+        statement.execute(sql);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectAllTest() {
+    String[] retArray =
+        new String[] {
+          "1,1,1", "2,2,2", "3,3,3", "4,4,4", "5,5,0", "6,6,1", "7,7,2", "8,8,3", "9,9,4"
+        };
+
+    String selectSql = "select * from root.**";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement1 = connection.createStatement();
+        Statement statement2 = connection.createStatement()) {
+      statement1.setFetchSize(10);
+      ResultSet resultSet1 = statement1.executeQuery(selectSql);
+      int cnt1 = 0;
+      while (resultSet1.next() && cnt1 < 5) {
+        String ans =
+            resultSet1.getString(TestConstant.TIMESTAMP_STR)
+                + ","
+                + resultSet1.getString("root.fans.d0.s0")
+                + ","
+                + resultSet1.getString("root.fans.d1.s0");
+        Assert.assertEquals(retArray[cnt1], ans);
+        cnt1++;
+      }
+
+      statement2.setFetchSize(10);
+      ResultSet resultSet2 = statement2.executeQuery(selectSql);
+      int cnt2 = 0;
+      while (resultSet2.next()) {
+        String ans =
+            resultSet2.getString(TestConstant.TIMESTAMP_STR)
+                + ","
+                + resultSet2.getString("root.fans.d0.s0")
+                + ","
+                + resultSet2.getString("root.fans.d1.s0");
+        Assert.assertEquals(retArray[cnt2], ans);
+        cnt2++;
+      }
+      Assert.assertEquals(9, cnt2);
+
+      // use do-while instead of while because in the previous while loop, we have executed the next
+      // function,
+      // and the cursor has been moved to the next position, so we should fetch that value first.
+      do {
+        String ans =
+            resultSet1.getString(TestConstant.TIMESTAMP_STR)
+                + ","
+                + resultSet1.getString("root.fans.d0.s0")
+                + ","
+                + resultSet1.getString("root.fans.d1.s0");
+        Assert.assertEquals(retArray[cnt1], ans);
+        cnt1++;
+      } while (resultSet1.next());
+      // Although the statement2 has the same sql as statement1, they shouldn't affect each other.
+      // So the statement1's ResultSet should also have 9 rows in total.
+      Assert.assertEquals(9, cnt1);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues2IT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues2IT.java
new file mode 100644
index 0000000..a44d1c8
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues2IT.java
@@ -0,0 +1,186 @@
+/*
+ * 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.relational.it.db.it.aligned;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertAlignedValues2IT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setAutoCreateSchemaEnabled(true)
+        .setMaxNumberOfPointsInPage(2);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testInsertAlignedWithEmptyPage() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database lz");
+      statement.execute("use \"lz\"");
+      statement.execute(
+          "create table dev (id1 string id, s1 int32 measurement, s2 int32 measurement, s3 int32 measurement)");
+      for (int i = 0; i < 100; i++) {
+        if (i == 99) {
+          statement.addBatch(
+              "insert into dev(id1,time,s1,s3) values("
+                  + "'GPS''"
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ")");
+        } else {
+          statement.addBatch(
+              "insert into dev(id1, time,s1,s2) values("
+                  + "'GPS'"
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ")");
+        }
+      }
+      statement.executeBatch();
+
+      statement.execute("flush");
+      int rowCount = 0;
+      try (ResultSet resultSet = statement.executeQuery("select time, s3 from dev")) {
+        while (resultSet.next()) {
+          assertEquals(99, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(1, rowCount);
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select time, s2 from dev")) {
+        rowCount = 0;
+        while (resultSet.next()) {
+          assertEquals(rowCount, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(99, rowCount);
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select time, s1 from dev")) {
+        rowCount = 0;
+        while (resultSet.next()) {
+          assertEquals(rowCount, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(100, rowCount);
+      }
+    }
+  }
+
+  @Test
+  public void testInsertAlignedWithEmptyPage2() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute(
+          "create table sg (id1 string id, s1 string measurement, s2 string measurement)");
+
+      statement.execute("insert into sg(id1, time, s1, s2) values('d1', 1,'aa','bb')");
+      statement.execute("insert into sg(id1, time, s1, s2) values('d1', 1,'aa','bb')");
+      statement.execute("insert into sg(id1, time, s1, s2) values('d2', 1,'aa','bb')");
+      statement.execute("flush");
+      statement.execute("insert into sg(id1, time, s1, s2) values('d1', 1,'aa','bb')");
+    }
+  }
+
+  @Test
+  public void testInsertComplexAlignedValues() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.addBatch("create database test");
+      statement.addBatch("use database \"test\"");
+      statement.addBatch(
+          "create table sg (id1 string id, s1 int32 measurement, s2 int32 measurement)");
+      statement.addBatch("insert into sg(id1, time, s1) values('id1', 3,1)");
+      statement.addBatch("insert into sg(id1, time, s1) values('id1', 3,1)");
+      statement.addBatch("insert into sg(id1, time, s1) values('id1', 1,1)");
+      statement.addBatch("insert into sg(id1, time, s1) values('id1', 2,1)");
+      statement.addBatch("insert into sg(id1, time, s2) values('id1', 2,2)");
+      statement.addBatch("insert into sg(id1, time, s2) values('id1', 1,2)");
+      statement.addBatch("insert into sg(id1, time, s2) values('id1', 3,2)");
+      statement.addBatch("insert into sg(id1, time, s3) values('id1', 1,3)");
+      statement.addBatch("insert into sg(id1, time, s3) values('id1', 3,3)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select count(s1), count(s2), count(s3) from sg")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(3, resultSet.getInt(1));
+        assertEquals(3, resultSet.getInt(2));
+        assertEquals(2, resultSet.getInt(3));
+
+        assertFalse(resultSet.next());
+      }
+
+      statement.execute("flush");
+      try (ResultSet resultSet =
+          statement.executeQuery("select count(s1), count(s2), count(s3) from sg")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(3, resultSet.getInt(1));
+        assertEquals(3, resultSet.getInt(2));
+        assertEquals(2, resultSet.getInt(3));
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues3IT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues3IT.java
new file mode 100644
index 0000000..d7c031d
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues3IT.java
@@ -0,0 +1,124 @@
+/*
+ * 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.relational.it.db.it.aligned;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertAlignedValues3IT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setAutoCreateSchemaEnabled(true)
+        .setMaxNumberOfPointsInPage(4);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testInsertAlignedWithEmptyPage2() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database lz");
+      statement.execute("use \"lz\"");
+      statement.execute(
+          "create table dev (id1 string id, s1 int32 measurement, s2 int32 measurement, s3 int32 measurement)");
+      for (int i = 0; i < 100; i++) {
+        if (i >= 49) {
+          statement.addBatch(
+              "insert into dev(id1,time,s1,s2,s3) values("
+                  + "GPS"
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ")");
+        } else {
+          statement.addBatch(
+              "insert into root.lz.dev.GPS(id1,time,s1,s2) values("
+                  + "GPS"
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ","
+                  + i
+                  + ")");
+        }
+      }
+      statement.executeBatch();
+      statement.execute("flush");
+      int rowCount = 0;
+      try (ResultSet resultSet = statement.executeQuery("select s3 from dev")) {
+        while (resultSet.next()) {
+          assertEquals(rowCount + 49, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(51, rowCount);
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select s2 from dev")) {
+        rowCount = 0;
+        while (resultSet.next()) {
+          assertEquals(rowCount, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(100, rowCount);
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select s1 from dev")) {
+        rowCount = 0;
+        while (resultSet.next()) {
+          assertEquals(rowCount, resultSet.getInt(2));
+          rowCount++;
+        }
+        assertEquals(100, rowCount);
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues4IT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues4IT.java
new file mode 100644
index 0000000..aa6b4e2
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValues4IT.java
@@ -0,0 +1,79 @@
+/*
+ * 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.relational.it.db.it.aligned;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertAlignedValues4IT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setAutoCreateSchemaEnabled(true)
+        .setPrimitiveArraySize(2);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testExtendTextColumn() {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute(
+          "create table sg (id1 string id, s1 string measurement, s2 string measurement)");
+      statement.execute("insert into sg(id1,time,s1,s2) values('d1',1,'test','test')");
+      statement.execute("insert into sg(id1,time,s1,s2) values('d1',2,'test','test')");
+      statement.execute("insert into sg(id1,time,s1,s2) values('d1',3,'test','test')");
+      statement.execute("insert into sg(id1,time,s1,s2) values('d1',4,'test','test')");
+      statement.execute("insert into sg(id1,time,s1,s3) values('d1',5,'test','test')");
+      statement.execute("insert into sg(id1,time,s1,s2) values('d1',6,'test','test')");
+      statement.execute("flush");
+      statement.execute("insert into sg(id1,time,s1,s3) values('d1',7,'test','test')");
+      fail();
+    } catch (SQLException ignored) {
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValuesIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValuesIT.java
new file mode 100644
index 0000000..b81dd97
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/aligned/IoTDBInsertAlignedValuesIT.java
@@ -0,0 +1,436 @@
+/*
+ * 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.relational.it.db.it.aligned;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBInsertAlignedValuesIT {
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setAutoCreateSchemaEnabled(true);
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testInsertAlignedValues() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.addBatch("create database t1");
+      statement.addBatch("use \"t1\"");
+      statement.addBatch(
+          "create table wf01 (id1 string id, status int32 measurement, temperature float measurement)");
+      statement.addBatch(
+          "insert into wf01(id1, time, status, temperature) values ('wt01', 4000, true, 17.1)");
+      statement.addBatch(
+          "insert into wf01(id1, time, status, temperature) values ('wt01', 5000, true, 20.1)");
+      statement.addBatch(
+          "insert into wf01(id1, time, status, temperature) values ('wt01', 6000, true, 22)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select time, status from wf01")) {
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertFalse(resultSet.next());
+      }
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select time, status, temperature from wf01")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(17.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(20.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(6000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(22, resultSet.getDouble(3), 0.1);
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertAlignedNullableValues() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+
+      statement.addBatch("create database t1");
+      statement.addBatch("use \"t1\"");
+      statement.addBatch(
+          "create table wf01 (id1 string id, status boolean measurement, temperature float measurement)");
+      statement.addBatch(
+          "insert into wf01(id1, time, status, temperature) values ('wt01', 4000, true, 17.1)");
+      statement.addBatch("insert into wf01(id1, time, status) values ('wt01', 5000, true)");
+      statement.addBatch("insert into wf01(id1, time, temperature) values ('wt01', 6000, 22)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select status from wf01")) {
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertFalse(resultSet.next());
+      }
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select time, status, temperature from wf01")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(17.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertNull(resultSet.getObject(3));
+
+        assertTrue(resultSet.next());
+        assertEquals(6000, resultSet.getLong(1));
+        assertNull(resultSet.getObject(2));
+        assertEquals(22.0d, resultSet.getObject(3));
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testUpdatingAlignedValues() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.addBatch("create database t1");
+      statement.addBatch("use \"t1\"");
+      statement.addBatch(
+          "create table wf01 (id1 string id, status boolean measurement, temperature float measurement)");
+      statement.addBatch(
+          "insert into wf01(id1, time, status, temperature) values ('wt01', 4000, true, 17.1)");
+      statement.addBatch("insert into wf01(id1, time, status) values ('wt01', 5000, true)");
+      statement.addBatch("insert into wf01(id1, time, temperature)values ('wt01', 5000, 20.1)");
+      statement.addBatch("insert into wf01(id1, time, temperature)values ('wt01', 6000, 22)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select time, status from wf01")) {
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertFalse(resultSet.next());
+      }
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select time, status, temperature from wf01")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(17.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(20.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(6000, resultSet.getLong(1));
+        assertNull(resultSet.getObject(2));
+        assertEquals(22.0d, resultSet.getObject(3));
+
+        assertFalse(resultSet.next());
+      }
+
+      statement.execute("flush");
+      try (ResultSet resultSet = statement.executeQuery("select time, status from wf01")) {
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertFalse(resultSet.next());
+      }
+
+      try (ResultSet resultSet =
+          statement.executeQuery("select time, status, temperature from wf01")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(17.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertTrue(resultSet.getBoolean(2));
+        assertEquals(20.1, resultSet.getDouble(3), 0.1);
+
+        assertTrue(resultSet.next());
+        assertEquals(6000, resultSet.getLong(1));
+        assertNull(resultSet.getObject(2));
+        assertEquals(22.0d, resultSet.getObject(3));
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertAlignedValuesWithSameTimestamp() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.addBatch("create database test");
+      statement.addBatch("use \"test\"");
+      statement.addBatch(
+          "create table sg (ids string id, s2 int32 measurement, s1 int32 measurement)");
+      statement.addBatch("insert into sg(id1,time,s2) values('d1',1,2)");
+      statement.addBatch("insert into sg(id1,time,s1) values('d1',1,2)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select time, s1, s2 from sg")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getLong(1));
+        assertEquals(2.0d, resultSet.getObject(2));
+        assertEquals(2.0d, resultSet.getObject(3));
+
+        assertFalse(resultSet.next());
+      }
+
+      statement.execute("flush");
+      try (ResultSet resultSet = statement.executeQuery("select time, s1, s2 from sg")) {
+
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getLong(1));
+        assertEquals(2.0d, resultSet.getObject(2));
+        assertEquals(2.0d, resultSet.getObject(3));
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertWithWrongMeasurementNum1() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database t1");
+      statement.execute("use \"t1\"");
+      statement.execute(
+          "create table wf01 (id1 string id, status int32, temperature int32 measurement)");
+      statement.execute(
+          "insert into wf01(id1, time, status, temperature) values('wt01', 11000, 100)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(e.getMessage().contains("failed"));
+    }
+  }
+
+  @Test
+  public void testInsertWithWrongMeasurementNum2() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database t1");
+      statement.execute("use \"t1\"");
+      statement.execute(
+          "create table wf01 (id1 string id, status int32, temperature int32 measurement)");
+      statement.execute(
+          "insert into wf01(id1, time, status, temperature) values('wt01', 11000, 100, 300, 400)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(e.getMessage(), e.getMessage().contains("failed"));
+    }
+  }
+
+  @Test(expected = Exception.class)
+  public void testInsertWithWrongType() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database lz");
+      statement.execute("use \"lz\"");
+      statement.execute(
+          "create table dev (id1 string id, latitude int32 measurement, longitude int32 measurement)");
+      statement.execute("insert into dev(id1,time,latitude,longitude) values('GPS', 1,1.3,6.7)");
+      fail();
+    }
+  }
+
+  @Test
+  @Ignore // TODO: delete
+  public void testInsertAlignedTimeseriesWithoutAligned() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "CREATE ALIGNED TIMESERIES root.lz.dev.GPS2(latitude INT32 encoding=PLAIN compressor=SNAPPY, longitude INT32 encoding=PLAIN compressor=SNAPPY) ");
+      statement.execute("insert into root.lz.dev.GPS2(time,latitude,longitude) values(1,123,456)");
+      // it's supported.
+    }
+  }
+
+  @Test
+  public void testInsertTimeseriesWithUnMatchedAlignedType() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("create ALIGNED timeseries root.db.d_aligned(s01 INT64 encoding=RLE)");
+      statement.execute("insert into root.db.d_aligned(time, s01) aligned values (4000, 123)");
+      statement.execute("insert into root.db.d_aligned(time, s01) values (5000, 456)");
+      statement.execute("create timeseries root.db.d_not_aligned.s01 INT64 encoding=RLE");
+      statement.execute("insert into root.db.d_not_aligned(time, s01) values (4000, 987)");
+      statement.execute("insert into root.db.d_not_aligned(time, s01) aligned values (5000, 654)");
+
+      try (ResultSet resultSet = statement.executeQuery("select s01 from root.db.d_aligned")) {
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertEquals(123, resultSet.getLong(2));
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertEquals(456, resultSet.getLong(2));
+
+        assertFalse(resultSet.next());
+      }
+
+      try (ResultSet resultSet = statement.executeQuery("select s01 from root.db.d_not_aligned")) {
+        assertTrue(resultSet.next());
+        assertEquals(4000, resultSet.getLong(1));
+        assertEquals(987, resultSet.getLong(2));
+
+        assertTrue(resultSet.next());
+        assertEquals(5000, resultSet.getLong(1));
+        assertEquals(654, resultSet.getLong(2));
+
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  @Ignore // TODO: delete
+  public void testInsertNonAlignedTimeseriesWithAligned() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE TIMESERIES root.lz.dev.GPS3.latitude with datatype=INT32");
+      statement.execute("CREATE TIMESERIES root.lz.dev.GPS3.longitude with datatype=INT32");
+      statement.execute(
+          "insert into root.lz.dev.GPS3(time,latitude,longitude) aligned values(1,123,456)");
+      // it's supported.
+    }
+  }
+
+  @Test
+  @Ignore // TODO: delete
+  public void testInsertAlignedValuesWithThreeLevelPath() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("insert into root.sg_device(time, status) aligned values (4000, true)");
+
+      try (ResultSet resultSet = statement.executeQuery("select ** from root")) {
+        assertTrue(resultSet.next());
+        assertTrue(resultSet.getBoolean(2));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertWithDuplicatedMeasurements() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database t1");
+      statement.execute("use \"t1\"");
+      statement.execute("create table wf01(id1 string id, s3 boolean measurement, status int32)");
+      statement.execute(
+          "insert into wf01(id1, time, s3, status, status) values('wt01', 100, true, 20.1, 20.2)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(
+          e.getMessage(),
+          e.getMessage().contains("Insertion contains duplicated measurement: status"));
+    }
+  }
+
+  @Test
+  public void testInsertMultiRows() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute(
+          "create table sg1 (id1 string id, s1 int32 measurement, s2 int32 measurement)");
+      statement.execute(
+          "insert into sg1(id1, time, s1, s2) values('d1', 10, 2, 2), ('d1', 11, 3, '3'), ('d1', 12,12.11,false)");
+      fail();
+    } catch (SQLException e) {
+      assertTrue(e.getMessage(), e.getMessage().contains("data type is not consistent"));
+    }
+  }
+
+  @Test
+  public void testInsertLargeNumber() {
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database test");
+      statement.execute("use \"test\"");
+      statement.execute(
+          "create table sg1 (id1 string id, s98 int64 measurement, s99 int64 measurement)");
+      statement.execute(
+          "insert into sg1(id1, time, s98, s99) values('d1', 10, 2, 271840880000000000000000)");
+    } catch (SQLException e) {
+      fail();
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBAutoCreateSchemaIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBAutoCreateSchemaIT.java
new file mode 100644
index 0000000..69a1148
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBAutoCreateSchemaIT.java
@@ -0,0 +1,274 @@
+/*
+ * 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.relational.it.db.it.schema;
+
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.TestConstant;
+import org.apache.iotdb.util.AbstractSchemaIT;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.Parameterized;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+@Ignore // TODO: delete this test
+public class IoTDBAutoCreateSchemaIT extends AbstractSchemaIT {
+
+  public IoTDBAutoCreateSchemaIT(SchemaTestMode schemaTestMode) {
+    super(schemaTestMode);
+  }
+
+  @Parameterized.BeforeParam
+  public static void before() throws Exception {
+    setUpEnvironment();
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @Parameterized.AfterParam
+  public static void after() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+    tearDownEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    clearSchema();
+  }
+
+  /** create timeseries without setting database */
+  @Test
+  public void createTimeseriesTest() throws ClassNotFoundException {
+    String[] sqls = {
+      "CREATE TIMESERIES root.sg0.d1.s2 WITH DATATYPE=INT32,ENCODING=RLE",
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,123)",
+    };
+    executeSQL(sqls);
+  }
+
+  /** insert data when database has been set but timeseries hasn't been created */
+  @Test
+  public void insertTest1() throws ClassNotFoundException {
+    String[] sqls = {
+      "CREATE DATABASE root.sg0",
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,123.123)",
+      "INSERT INTO root.sg0.d1(timestamp,s3) values(1,\"abc\")",
+    };
+    executeSQL(sqls);
+  }
+
+  /** insert data when database hasn't been set and timeseries hasn't been created */
+  @Test
+  public void insertTest2() throws ClassNotFoundException {
+    String[] sqls = {
+      "INSERT INTO root.sg0.d1(timestamp,s2) values(1,\"abc\")",
+      "INSERT INTO root.sg0.d2(timestamp,s3) values(1,123.123)",
+      "INSERT INTO root.sg0.d2(timestamp,s4) values(1,123456)",
+    };
+    executeSQL(sqls);
+  }
+
+  private void executeSQL(String[] sqls) throws ClassNotFoundException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String result = "";
+      Long now_start = 0L;
+      boolean cmp = false;
+
+      for (String sql : sqls) {
+        if (cmp) {
+          Assert.assertEquals(sql, result);
+          cmp = false;
+        } else if (sql.equals("SHOW TIMESERIES")) {
+          DatabaseMetaData data = connection.getMetaData();
+          result = data.toString();
+          cmp = true;
+        } else {
+          if (sql.contains("NOW()") && now_start == 0L) {
+            now_start = System.currentTimeMillis();
+          }
+
+          if (sql.split(" ")[0].equals("SELECT")) {
+            ResultSet resultSet = statement.executeQuery(sql);
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            int count = metaData.getColumnCount();
+            String[] column = new String[count];
+            for (int i = 0; i < count; i++) {
+              column[i] = metaData.getColumnName(i + 1);
+            }
+            result = "";
+            while (resultSet.next()) {
+              for (int i = 1; i <= count; i++) {
+                if (now_start > 0L && column[i - 1].equals(TestConstant.TIMESTAMP_STR)) {
+                  String timestr = resultSet.getString(i);
+                  Long tn = Long.valueOf(timestr);
+                  Long now = System.currentTimeMillis();
+                  if (tn >= now_start && tn <= now) {
+                    timestr = "NOW()";
+                  }
+                  result += timestr + ',';
+                } else {
+                  result += resultSet.getString(i) + ',';
+                }
+              }
+              result += '\n';
+            }
+            cmp = true;
+          }
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * test if automatically creating a time series will cause the database with same name to
+   * disappear
+   */
+  @Test
+  public void testInsertAutoCreate2() throws Exception {
+    String storageGroup = "root.sg2.a.b.c";
+    String timeSeriesPrefix = "root.sg2.a.b";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(String.format("CREATE DATABASE %s", storageGroup));
+      try {
+        statement.execute(
+            String.format("INSERT INTO %s(timestamp, c) values(123, \"aabb\")", timeSeriesPrefix));
+      } catch (SQLException ignored) {
+      }
+
+      // ensure that current database in cache is right.
+      InsertAutoCreate2Tool(statement, storageGroup, timeSeriesPrefix);
+    }
+    // todo restart test
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure that database in cache is right after recovering.
+    //    InsertAutoCreate2Tool(storageGroup, timeSeriesPrefix);
+  }
+
+  private void InsertAutoCreate2Tool(
+      Statement statement, String storageGroup, String timeSeriesPrefix) throws SQLException {
+    Set<String> resultList = new HashSet<>();
+    try (ResultSet resultSet = statement.executeQuery("show timeseries")) {
+      while (resultSet.next()) {
+        String str = resultSet.getString(ColumnHeaderConstant.TIMESERIES);
+        resultList.add(str);
+      }
+    }
+    Assert.assertFalse(resultList.contains(timeSeriesPrefix + "c"));
+
+    resultList.clear();
+    try (ResultSet resultSet = statement.executeQuery("show databases")) {
+      while (resultSet.next()) {
+        resultList.add(resultSet.getString(ColumnHeaderConstant.DATABASE));
+      }
+    }
+    Assert.assertTrue(resultList.contains(storageGroup));
+  }
+
+  /**
+   * insert data when database hasn't been set, timeseries hasn't been created and have null values
+   */
+  @Test
+  public void testInsertAutoCreate3() throws SQLException {
+    String[] sqls = {
+      "INSERT INTO root.sg0.d3(timestamp,s1) values(1,null)",
+      "INSERT INTO root.sg0.d3(timestamp,s1,s2) values(1,null,2)",
+    };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String sql : sqls) {
+        try {
+          statement.execute(sql);
+        } catch (SQLException e) {
+          Assert.assertTrue(e.getMessage().contains("Path [root.sg0.d3.s1] does not exist"));
+        }
+      }
+    }
+  }
+
+  /**
+   * insert data when database hasn't been set, timeseries hasn't been created and have null values
+   */
+  @Test
+  public void testAutoCreateDataType() throws SQLException {
+    String SQL =
+        "INSERT INTO root.sg0.d1(time,s1,s2,s3,s4,s5,s6) values(1,true,1,now(),X'cafe',\"string\",\"2024-01-01\")";
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(SQL);
+      ResultSet resultSet = statement.executeQuery("show timeseries");
+      while (resultSet.next()) {
+        switch (resultSet.getString(ColumnHeaderConstant.TIMESERIES)) {
+          case "root.sg0.d1.s1":
+            assertEquals(
+                TSDataType.BOOLEAN.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+          case "root.sg0.d1.s2":
+            assertEquals(
+                TSDataType.DOUBLE.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+          case "root.sg0.d1.s3":
+            assertEquals(
+                TSDataType.INT64.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+          case "root.sg0.d1.s4":
+            assertEquals(
+                TSDataType.BLOB.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+          case "root.sg0.d1.s5":
+            assertEquals(
+                TSDataType.TEXT.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+          case "root.sg0.d1.s6":
+            assertEquals(
+                TSDataType.TEXT.toString(), resultSet.getString(ColumnHeaderConstant.DATATYPE));
+            break;
+        }
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
new file mode 100644
index 0000000..a6b7450
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateAlignedTimeseriesIT.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.relational.it.db.it.schema;
+
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.util.AbstractSchemaIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.Parameterized;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+public class IoTDBCreateAlignedTimeseriesIT extends AbstractSchemaIT {
+
+  public IoTDBCreateAlignedTimeseriesIT(SchemaTestMode schemaTestMode) {
+    super(schemaTestMode);
+  }
+
+  @Parameterized.BeforeParam
+  public static void before() throws Exception {
+    setUpEnvironment();
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @Parameterized.AfterParam
+  public static void after() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+    tearDownEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    clearSchema();
+  }
+
+  @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
+  public void testCreateAlignedTimeseries() throws Exception {
+    String[] timeSeriesArray =
+        new String[] {
+          "root.sg1.d1.vector1.s1,FLOAT,PLAIN,UNCOMPRESSED", "root.sg1.d1.vector1.s2,INT64,RLE,LZ4"
+        };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.sg1");
+      try {
+        statement.execute(
+            "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 FLOAT encoding=PLAIN compressor=UNCOMPRESSED,s2 INT64 encoding=RLE)");
+      } catch (SQLException ignored) {
+      }
+
+      // ensure that current database in cache is right.
+      assertTimeseriesEquals(timeSeriesArray);
+    }
+    // todo test restart
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure database in cache is right after recovering.
+    //    assertTimeseriesEquals(timeSeriesArray);
+  }
+
+  @Test
+  public void testCreateAlignedTimeseriesWithDeletion() throws Exception {
+    String[] timeSeriesArray =
+        new String[] {
+          "root.sg1.d1.vector1.s1,DOUBLE,PLAIN,SNAPPY", "root.sg1.d1.vector1.s2,INT64,RLE,LZ4"
+        };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE root.sg1");
+      try {
+        statement.execute(
+            "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 FLOAT encoding=PLAIN compressor=UNCOMPRESSED,s2 INT64 encoding=RLE)");
+        statement.execute("DELETE TIMESERIES root.sg1.d1.vector1.s1");
+        statement.execute(
+            "CREATE ALIGNED TIMESERIES root.sg1.d1.vector1(s1 DOUBLE encoding=PLAIN compressor=SNAPPY)");
+      } catch (SQLException e) {
+        e.printStackTrace();
+      }
+    }
+
+    // ensure that current database in cache is right.
+    assertTimeseriesEquals(timeSeriesArray);
+
+    // todo
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+
+    // ensure database in cache is right after recovering.
+    assertTimeseriesEquals(timeSeriesArray);
+  }
+
+  private void assertTimeseriesEquals(String[] timeSeriesArray) throws SQLException {
+
+    int count = 0;
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement();
+        ResultSet resultSet = statement.executeQuery("SHOW TIMESERIES")) {
+      while (resultSet.next()) {
+        String ActualResult =
+            resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+                + ","
+                + resultSet.getString(ColumnHeaderConstant.DATATYPE)
+                + ","
+                + resultSet.getString(ColumnHeaderConstant.ENCODING)
+                + ","
+                + resultSet.getString(ColumnHeaderConstant.COMPRESSION);
+        Assert.assertEquals(timeSeriesArray[count], ActualResult);
+        count++;
+      }
+    }
+    Assert.assertEquals(timeSeriesArray.length, count);
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateStorageGroupIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateStorageGroupIT.java
new file mode 100644
index 0000000..761ff14
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateStorageGroupIT.java
@@ -0,0 +1,155 @@
+/*
+ * 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.relational.it.db.it.schema;
+
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.util.AbstractSchemaIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.Parameterized;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBCreateStorageGroupIT extends AbstractSchemaIT {
+
+  public IoTDBCreateStorageGroupIT(SchemaTestMode schemaTestMode) {
+    super(schemaTestMode);
+  }
+
+  @Parameterized.BeforeParam
+  public static void before() throws Exception {
+    setUpEnvironment();
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @Parameterized.AfterParam
+  public static void after() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+    tearDownEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    clearSchema();
+  }
+
+  /** The test creates three databases */
+  @Test
+  public void testCreateStorageGroup() throws Exception {
+    String[] storageGroups = {"sg1", "sg2", "sg3"};
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      for (String storageGroup : storageGroups) {
+        statement.execute(String.format("create database %s", storageGroup));
+      }
+
+      // ensure that current StorageGroup in cache is right.
+      createStorageGroupTool(statement, storageGroups);
+    }
+    // todo test restart
+    //    EnvironmentUtils.stopDaemon();
+    //    setUp();
+    //
+    //    // ensure StorageGroup in cache is right after recovering.
+    //    createStorageGroupTool(storageGroups);
+  }
+
+  private void createStorageGroupTool(Statement statement, String[] storageGroups)
+      throws SQLException {
+
+    List<String> resultList = new ArrayList<>();
+    try (ResultSet resultSet = statement.executeQuery("SHOW DATABASES")) {
+      while (resultSet.next()) {
+        String storageGroupPath = resultSet.getString(ColumnHeaderConstant.DATABASE);
+        resultList.add(storageGroupPath);
+      }
+    }
+    Assert.assertEquals(3, resultList.size());
+
+    resultList = resultList.stream().sorted().collect(Collectors.toList());
+
+    Assert.assertEquals(storageGroups[0], resultList.get(0));
+    Assert.assertEquals(storageGroups[1], resultList.get(1));
+    Assert.assertEquals(storageGroups[2], resultList.get(2));
+  }
+
+  /** Test creating a database that path is an existence database */
+  @Test
+  public void testCreateExistStorageGroup1() throws Exception {
+    String storageGroup = "sg";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute(String.format("CREATE DATABASE %s", storageGroup));
+
+      try {
+        statement.execute(String.format("create database %s", storageGroup));
+        fail();
+      } catch (SQLException e) {
+        Assert.assertEquals(
+            TSStatusCode.DATABASE_ALREADY_EXISTS.getStatusCode() + ": Database sg already exists",
+            e.getMessage());
+      }
+    }
+  }
+
+  /** Test the parent node has been set as a database */
+  @Test
+  @Ignore // TODO: delete this test
+  public void testCreateExistStorageGroup2() throws Exception {
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("create database root.sg");
+
+      try {
+        statement.execute("create database root.sg.`device`");
+        fail();
+      } catch (SQLException e) {
+        Assert.assertEquals(
+            TSStatusCode.DATABASE_ALREADY_EXISTS.getStatusCode()
+                + ": root.sg has already been created as database",
+            e.getMessage());
+      }
+    }
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateTimeseriesIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateTimeseriesIT.java
new file mode 100644
index 0000000..6468938
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/schema/IoTDBCreateTimeseriesIT.java
@@ -0,0 +1,300 @@
+/*
+ * 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.relational.it.db.it.schema;
+
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.util.AbstractSchemaIT;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.Parameterized;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test which will start the
+ * IoTDB server should be defined as integration test.
+ */
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+@Ignore // TODO: delete this test
+public class IoTDBCreateTimeseriesIT extends AbstractSchemaIT {
+
+  public IoTDBCreateTimeseriesIT(SchemaTestMode schemaTestMode) {
+    super(schemaTestMode);
+  }
+
+  @Parameterized.BeforeParam
+  public static void before() throws Exception {
+    setUpEnvironment();
+    EnvFactory.getEnv().initClusterEnvironment();
+  }
+
+  @Parameterized.AfterParam
+  public static void after() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+    tearDownEnvironment();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    clearSchema();
+  }
+
+  /** Test if creating a time series will cause the database with same name to disappear */
+  @Test
+  public void testCreateTimeseries() throws Exception {
+    String storageGroup = "root.sg1.a.b.c";
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(String.format("CREATE DATABASE %s", storageGroup));
+      statement.execute(
+          String.format(
+              "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=SNAPPY",
+              storageGroup));
+
+    } catch (Exception ignored) {
+    }
+
+    // ensure that current database in cache is right.
+    createTimeSeriesTool(storageGroup);
+  }
+
+  private void createTimeSeriesTool(String storageGroup) throws SQLException {
+    Set<String> resultList = new HashSet<>();
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement();
+        ResultSet resultSet = statement.executeQuery("show timeseries")) {
+      while (resultSet.next()) {
+        String str = resultSet.getString(ColumnHeaderConstant.TIMESERIES);
+        resultList.add(str);
+      }
+    }
+    Assert.assertFalse(resultList.contains(storageGroup));
+    resultList.clear();
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement();
+        ResultSet resultSet = statement.executeQuery("SHOW DATABASES")) {
+      while (resultSet.next()) {
+        String res = resultSet.getString(ColumnHeaderConstant.DATABASE);
+        resultList.add(res);
+      }
+    }
+    Assert.assertTrue(resultList.contains(storageGroup));
+  }
+
+  @Test
+  public void testCreateTimeseriesWithSpecialCharacter() throws Exception {
+    try (Connection connection = EnvFactory.getEnv().getConnection()) {
+      try (Statement statement = connection.createStatement()) {
+        statement.execute(
+            String.format(
+                "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=SNAPPY",
+                "root.sg.d.a\".\"b"));
+        fail();
+      } catch (SQLException ignored) {
+      }
+      try (Statement statement = connection.createStatement()) {
+        statement.execute(
+            String.format(
+                "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=SNAPPY",
+                "root.sg.d.a“(Φ)”b"));
+        fail();
+      } catch (SQLException ignored) {
+      }
+      try (Statement statement = connection.createStatement()) {
+        statement.execute(
+            String.format(
+                "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=SNAPPY",
+                "root.sg.d.a>b"));
+        fail();
+      } catch (SQLException ignored) {
+      }
+    }
+
+    String[] timeSeriesArray = {
+      "root.sg.d.`a.b`", "root.sg.d.`a“(Φ)”b`", "root.sg.d.`a>b`", "root.sg.d.`0e38`"
+    };
+    String[] timeSeriesResArray = {
+      "root.sg.d.`a.b`", "root.sg.d.`a“(Φ)”b`", "root.sg.d.`a>b`", "root.sg.d.`0e38`",
+    };
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      for (String timeSeries : timeSeriesArray) {
+        statement.execute(
+            String.format(
+                "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=SNAPPY",
+                timeSeries));
+      }
+    }
+
+    // ensure that current timeseries in cache is right.
+    createTimeSeriesWithSpecialCharacterTool(timeSeriesResArray);
+  }
+
+  private void createTimeSeriesWithSpecialCharacterTool(String[] timeSeriesArray)
+      throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement();
+        ResultSet resultSet = statement.executeQuery("count timeseries root.sg.**")) {
+      while (resultSet.next()) {
+        long count = resultSet.getLong(1);
+        Assert.assertEquals(timeSeriesArray.length, count);
+      }
+    }
+  }
+
+  @Test
+  public void testCreateTimeSeriesWithWrongAttribute() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format("create timeseries %s with datatype=INT64, datatype = test", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(String.format("create timeseries %s with encoding=plain", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format(
+              "create timeseries %s with encoding=plain, compressor=snappy", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format("create timeseries %s with datatype=float, encoding=plan", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format("create timeseries %s with datatype=INT64, encoding=test", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format(
+              "create timeseries %s with datatype=INT64, encoding=test, compression=test",
+              "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format("create timeseries %s with datatype=INT64,compression=test", "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          String.format(
+              "create timeseries %s with datatype=INT64, encoding=PLAIN, compression=test",
+              "root.sg.a"));
+      fail();
+    } catch (SQLException ignored) {
+    }
+  }
+
+  @Test
+  public void testQueryDataFromTimeSeriesWithoutData() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("create timeseries root.sg2.d.s1 with datatype=INT64");
+    } catch (SQLException ignored) {
+      fail();
+    }
+    int cnt = 0;
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement();
+        ResultSet resultSet = statement.executeQuery("select s1 from root.sg2.d")) {
+      while (resultSet.next()) {
+        cnt++;
+      }
+    } catch (SQLException e) {
+      fail();
+    }
+    Assert.assertEquals(0, cnt);
+  }
+
+  @Test
+  public void testIllegalInput() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("create timeseries root.sg2.d.s1 with datatype=INT64");
+      assertThrows(
+          "Unsupported datatype: UNKNOWN",
+          SQLException.class,
+          () -> statement.execute("create timeseries root.sg2.d.s1 with datatype=UNKNOWN"));
+      assertThrows(
+          "Unsupported datatype: VECTOR",
+          SQLException.class,
+          () -> statement.execute("create timeseries root.sg2.d.s1 with datatype=VECTOR"));
+      assertThrows(
+          "Unsupported datatype: YES",
+          SQLException.class,
+          () -> statement.execute("create timeseries root.sg2.d.s1 with datatype=YES"));
+      assertThrows(
+          "Unsupported datatype: UNKNOWN",
+          SQLException.class,
+          () -> statement.execute("create device template t1 (s1 UNKNOWN, s2 boolean)"));
+      assertThrows(
+          "Unsupported datatype: VECTOR",
+          SQLException.class,
+          () -> statement.execute("create device template t1 (s1 VECTOR, s2 boolean)"));
+    } catch (SQLException ignored) {
+      fail();
+    }
+  }
+}