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

haonan pushed a commit to branch rc/1.3.1
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 6252a973c499d9ad8809f1e8f275a036181cecd4
Author: Jackie Tien <[email protected]>
AuthorDate: Wed Feb 28 08:38:11 2024 +0800

    [IOTDB-6300] Support place time column at any column index in insert 
statement
---
 .../db/it/IOTDBInsertWithTimeAtAnyIndexIT.java     |  99 ++++++++++++++++++++
 .../iotdb/db/it/IoTDBInsertWithoutTimeIT.java      |   8 +-
 .../it/IoTDBSyntaxConventionStringLiteralIT.java   |   8 +-
 .../aggregation/IoTDBCountTimeAlignedDeviceIT.java |   2 +-
 .../org/apache/iotdb/db/it/cq/IoTDBCQExecIT.java   |  10 +-
 .../apache/iotdb/db/it/cq/IoTDBCQExecInNsIT.java   |  10 +-
 .../apache/iotdb/db/it/cq/IoTDBCQExecInUsIT.java   |  10 +-
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |  18 ++--
 .../db/queryengine/plan/parser/ASTVisitor.java     | 104 ++++++++++++---------
 9 files changed, 195 insertions(+), 74 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java
new file mode 100644
index 00000000000..3db755bb547
--- /dev/null
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBInsertWithTimeAtAnyIndexIT.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.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("insert into root.db.d1(s1, s2, time) aligned values 
(2, 3, 1)");
+      statement.addBatch("insert into root.db.d1(s1, time, s2) aligned values 
(20, 10, 30)");
+      statement.addBatch("insert into root.db.d1(`time`, s1, s2) aligned 
values (100, 200, 300)");
+      statement.executeBatch();
+
+      try (ResultSet resultSet = statement.executeQuery("select s1 from 
root.db.d1")) {
+        assertTrue(resultSet.next());
+        assertEquals(1, resultSet.getLong(1));
+        assertEquals(2, resultSet.getFloat(2), 0.00001);
+        assertTrue(resultSet.next());
+        assertEquals(10, resultSet.getLong(1));
+        assertEquals(20, resultSet.getFloat(2), 0.00001);
+        assertTrue(resultSet.next());
+        assertEquals(100, resultSet.getLong(1));
+        assertEquals(200, resultSet.getFloat(2), 0.00001);
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
+  @Test
+  public void testInsertMultiTime() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.addBatch(
+            "insert into root.db.d1(s1, s2, time, time) aligned values (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/db/it/IoTDBInsertWithoutTimeIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBInsertWithoutTimeIT.java
index d9d576ea20a..62d04de083a 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBInsertWithoutTimeIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBInsertWithoutTimeIT.java
@@ -101,7 +101,8 @@ public class IoTDBInsertWithoutTimeIT {
   @Test
   public void testInsertWithoutValueColumns() {
     assertNonQueryTestFail(
-        "insert into root.sg1.d1(time) values (1)", "Error occurred while 
parsing SQL");
+        "insert into root.sg1.d1(time) values (1)",
+        "InsertStatement should contain at least one measurement");
   }
 
   @Test
@@ -117,9 +118,10 @@ public class IoTDBInsertWithoutTimeIT {
   @Test
   public void testInsertWithMultiTimesColumns() {
     assertNonQueryTestFail(
-        "insert into root.sg1.d1(time, time) values (1, 1)", "Error occurred 
while parsing SQL");
+        "insert into root.sg1.d1(time, time) values (1, 1)",
+        "One row should only have one time value");
     assertNonQueryTestFail(
         "insert into root.sg1.d1(time, s1, time) values (1, 1, 1)",
-        "Error occurred while parsing SQL");
+        "One row should only have one time value");
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
index ceadf96ab3e..27a88f44736 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
@@ -179,7 +179,7 @@ public class IoTDBSyntaxConventionStringLiteralIT {
     String errorMsg =
         TSStatusCode.SQL_PARSE_ERROR.getStatusCode()
             + ": Error occurred while parsing SQL to physical plan: "
-            + "line 1:45 no viable alternative at input '(1, string'";
+            + "line 1:45 mismatched input 'string' expecting {FALSE, NAN, NOW, 
NULL, TRUE, '-', '+', '/', '.', STRING_LITERAL, DATETIME_LITERAL, 
INTEGER_LITERAL, EXPONENT_NUM_PART}";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       statement.execute("CREATE TIMESERIES root.sg1.d1.s1 TEXT");
@@ -198,7 +198,7 @@ public class IoTDBSyntaxConventionStringLiteralIT {
     String errorMsg1 =
         TSStatusCode.SQL_PARSE_ERROR.getStatusCode()
             + ": Error occurred while parsing SQL to physical plan: "
-            + "line 1:45 no viable alternative at input '(1, `string`'";
+            + "line 1:45 mismatched input '`string`' expecting {FALSE, NAN, 
NOW, NULL, TRUE, '-', '+', '/', '.', STRING_LITERAL, DATETIME_LITERAL, 
INTEGER_LITERAL, EXPONENT_NUM_PART}";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       // wrap STRING_LITERAL with ``
@@ -211,7 +211,7 @@ public class IoTDBSyntaxConventionStringLiteralIT {
     String errorMsg2 =
         TSStatusCode.SQL_PARSE_ERROR.getStatusCode()
             + ": Error occurred while parsing SQL to physical plan: "
-            + "line 1:53 token recognition error at: '')'";
+            + "line 1:47 extraneous input 'string' expecting {',', ')'}";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       // single ' in ''
@@ -224,7 +224,7 @@ public class IoTDBSyntaxConventionStringLiteralIT {
     String errorMsg3 =
         TSStatusCode.SQL_PARSE_ERROR.getStatusCode()
             + ": Error occurred while parsing SQL to physical plan: "
-            + "line 1:53 token recognition error at: '\")'";
+            + "line 1:47 extraneous input 'string' expecting {',', ')'}";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       // single " in ""
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBCountTimeAlignedDeviceIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBCountTimeAlignedDeviceIT.java
index d1647cd3ef5..621a3867a26 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBCountTimeAlignedDeviceIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBCountTimeAlignedDeviceIT.java
@@ -50,7 +50,7 @@ public class IoTDBCountTimeAlignedDeviceIT {
         "CREATE ALIGNED TIMESERIES root.aligned.downsampling.d2(s1 INT32, s2 
INT32);",
         "INSERT INTO root.aligned.downsampling.d1(time, s1, s2) ALIGNED 
VALUES(0, 0, null), (1, null, 1), "
             + "(2, null, 2), (4,4,null), (5,5,5), (7,null,7), (8,8,8), 
(9,null,9);",
-        "INSERT INTO root.aligned.downsampling.d2(time, s1, s2) ALIGNED 
VALUES(0,null,0) (1, 1, null), (2,2,null), "
+        "INSERT INTO root.aligned.downsampling.d2(time, s1, s2) ALIGNED 
VALUES(0,null,0), (1, 1, null), (2,2,null), "
             + "(4,null,4), (5,5,5), (7,7,null), (8,8,8);",
 
         // test group by variation
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecIT.java 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecIT.java
index c83510beacf..ea00bbfa646 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecIT.java
@@ -55,7 +55,7 @@ public class IoTDBCQExecIT {
   @Test
   public void testCQExecution1() {
     String insertTemplate =
-        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis();
@@ -142,7 +142,7 @@ public class IoTDBCQExecIT {
   @Test
   public void testCQExecution2() {
     String insertTemplate =
-        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis();
@@ -230,7 +230,7 @@ public class IoTDBCQExecIT {
   @Test
   public void testCQExecution3() {
     String insertTemplate =
-        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis();
@@ -329,7 +329,7 @@ public class IoTDBCQExecIT {
   @Test
   public void testCQExecution4() {
     String insertTemplate =
-        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis();
@@ -415,7 +415,7 @@ public class IoTDBCQExecIT {
   @Test
   public void testCQExecution5() {
     String insertTemplate =
-        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis();
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInNsIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInNsIT.java
index 453cd73cbd7..80acdb14087 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInNsIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInNsIT.java
@@ -57,7 +57,7 @@ public class IoTDBCQExecInNsIT {
   @Test
   public void testCQExecution1() {
     String insertTemplate =
-        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000_000L;
@@ -147,7 +147,7 @@ public class IoTDBCQExecInNsIT {
   @Test
   public void testCQExecution2() {
     String insertTemplate =
-        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000_000L;
@@ -239,7 +239,7 @@ public class IoTDBCQExecInNsIT {
   @Test
   public void testCQExecution3() {
     String insertTemplate =
-        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000_000L;
@@ -338,7 +338,7 @@ public class IoTDBCQExecInNsIT {
   @Test
   public void testCQExecution4() {
     String insertTemplate =
-        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000_000L;
@@ -424,7 +424,7 @@ public class IoTDBCQExecInNsIT {
   @Test
   public void testCQExecution5() {
     String insertTemplate =
-        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000_000L;
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInUsIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInUsIT.java
index 14a03e7e66f..c9971af3afb 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInUsIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/cq/IoTDBCQExecInUsIT.java
@@ -57,7 +57,7 @@ public class IoTDBCQExecInUsIT {
   @Test
   public void testCQExecution1() {
     String insertTemplate =
-        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d1(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000L;
@@ -147,7 +147,7 @@ public class IoTDBCQExecInUsIT {
   @Test
   public void testCQExecution2() {
     String insertTemplate =
-        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d2(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000L;
@@ -239,7 +239,7 @@ public class IoTDBCQExecInUsIT {
   @Test
   public void testCQExecution3() {
     String insertTemplate =
-        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d3(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000L;
@@ -338,7 +338,7 @@ public class IoTDBCQExecInUsIT {
   @Test
   public void testCQExecution4() {
     String insertTemplate =
-        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d4(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000L;
@@ -424,7 +424,7 @@ public class IoTDBCQExecInUsIT {
   @Test
   public void testCQExecution5() {
     String insertTemplate =
-        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d) (%d, %d) (%d, %d) 
(%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d) (%d, %d)";
+        "INSERT INTO root.sg.d5(time, s1) VALUES (%d, %d), (%d, %d), (%d, %d), 
(%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d), (%d, %d)";
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       long now = System.currentTimeMillis() * 1_000L;
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 7c4ae5ebe0c..56568d653da 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -787,21 +787,21 @@ insertStatement
     ;
 
 insertColumnsSpec
-    : LR_BRACKET (TIMESTAMP|TIME)? (COMMA? nodeNameWithoutWildcard)+ RR_BRACKET
+    : LR_BRACKET insertColumn (COMMA insertColumn)* RR_BRACKET
     ;
 
-insertValuesSpec
-    : (COMMA? insertMultiValue)*
+insertColumn
+    : identifier
+    | TIME
+    | TIMESTAMP
     ;
 
-insertMultiValue
-    : LR_BRACKET timeValue (COMMA measurementValue)+ RR_BRACKET
-    | LR_BRACKET (measurementValue COMMA?)+ RR_BRACKET
+insertValuesSpec
+    : row (COMMA row)*
     ;
 
-measurementValue
-    : constant
-    | LR_BRACKET constant (COMMA constant)+ RR_BRACKET
+row
+    : LR_BRACKET constant (COMMA constant)* RR_BRACKET
     ;
 
 // Delete Statement
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index fff5c53ef66..b3307e2ad2f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -1800,78 +1800,98 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
   public Statement visitInsertStatement(IoTDBSqlParser.InsertStatementContext 
ctx) {
     InsertStatement insertStatement = new InsertStatement();
     insertStatement.setDevice(parsePrefixPath(ctx.prefixPath()));
-    boolean isTimeDefault = parseInsertColumnSpec(ctx.insertColumnsSpec(), 
insertStatement);
-    parseInsertValuesSpec(ctx.insertValuesSpec(), insertStatement, 
isTimeDefault);
+    int timeIndex = parseInsertColumnSpec(ctx.insertColumnsSpec(), 
insertStatement);
+    parseInsertValuesSpec(ctx.insertValuesSpec(), insertStatement, timeIndex);
     insertStatement.setAligned(ctx.ALIGNED() != null);
     return insertStatement;
   }
 
-  private boolean parseInsertColumnSpec(
+  private int parseInsertColumnSpec(
       IoTDBSqlParser.InsertColumnsSpecContext ctx, InsertStatement 
insertStatement) {
     List<String> measurementList = new ArrayList<>();
-    for (IoTDBSqlParser.NodeNameWithoutWildcardContext measurementName :
-        ctx.nodeNameWithoutWildcard()) {
-      measurementList.add(parseNodeNameWithoutWildCard(measurementName));
+    int timeIndex = -1;
+
+    for (int i = 0, size = ctx.insertColumn().size(); i < size; i++) {
+      String measurement = parseInsertColumn(ctx.insertColumn(i));
+      if ("time".equalsIgnoreCase(measurement) || 
"timestamp".equalsIgnoreCase(measurement)) {
+        if (timeIndex != -1) {
+          throw new SemanticException("One row should only have one time 
value");
+        } else {
+          timeIndex = i;
+        }
+      } else {
+        measurementList.add(measurement);
+      }
+    }
+    if (measurementList.isEmpty()) {
+      throw new SemanticException("InsertStatement should contain at least one 
measurement");
     }
     insertStatement.setMeasurementList(measurementList.toArray(new String[0]));
-    return (ctx.TIME() == null && ctx.TIMESTAMP() == null);
+    return timeIndex;
+  }
+
+  private String parseInsertColumn(IoTDBSqlParser.InsertColumnContext 
columnContext) {
+    return parseNodeString(columnContext.getText());
   }
 
   private void parseInsertValuesSpec(
-      IoTDBSqlParser.InsertValuesSpecContext ctx,
-      InsertStatement insertStatement,
-      boolean isTimeDefault) {
-    List<IoTDBSqlParser.InsertMultiValueContext> insertMultiValues = 
ctx.insertMultiValue();
+      IoTDBSqlParser.InsertValuesSpecContext ctx, InsertStatement 
insertStatement, int timeIndex) {
+    List<IoTDBSqlParser.RowContext> rows = ctx.row();
+    if (timeIndex == -1 && rows.size() != 1) {
+      throw new SemanticException("need timestamps when insert multi rows");
+    }
     List<String[]> valuesList = new ArrayList<>();
-    long[] timeArray = new long[insertMultiValues.size()];
-    for (int i = 0; i < insertMultiValues.size(); i++) {
+    long[] timeArray = new long[rows.size()];
+    for (int i = 0, size = rows.size(); i < size; i++) {
+      IoTDBSqlParser.RowContext row = rows.get(i);
       // parse timestamp
       long timestamp;
       List<String> valueList = new ArrayList<>();
-
-      if (insertMultiValues.get(i).timeValue() != null) {
-        if (isTimeDefault) {
-          if (insertMultiValues.size() != 1) {
-            throw new SemanticException("need timestamps when insert multi 
rows");
-          }
-          valueList.add(insertMultiValues.get(i).timeValue().getText());
-          timestamp = CommonDateTimeUtils.currentTime();
-        } else {
-          timestamp =
-              parseTimeValue(
-                  insertMultiValues.get(i).timeValue(), 
CommonDateTimeUtils.currentTime());
-          TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
-        }
+      // using now() instead
+      if (timeIndex == -1) {
+        timestamp = CommonDateTimeUtils.currentTime();
       } else {
-        if (!isTimeDefault) {
-          throw new SemanticException(
-              "the measurementList's size is not consistent with the 
valueList's size");
-        }
-        if (insertMultiValues.size() != 1) {
-          throw new SemanticException("need timestamps when insert multi 
rows");
-        }
-        timestamp = parseDateFormat(SqlConstant.NOW_FUNC);
+        timestamp = parseTimeValue(row.constant(timeIndex));
+        TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
       }
       timeArray[i] = timestamp;
 
       // parse values
-      List<IoTDBSqlParser.MeasurementValueContext> values =
-          insertMultiValues.get(i).measurementValue();
-      for (IoTDBSqlParser.MeasurementValueContext value : values) {
-        for (IoTDBSqlParser.ConstantContext constant : value.constant()) {
-          if (constant.STRING_LITERAL() != null) {
-            valueList.add(parseStringLiteralInInsertValue(constant.getText()));
+      List<ConstantContext> values = row.constant();
+      for (int j = 0, columnCount = values.size(); j < columnCount; j++) {
+        if (j != timeIndex) {
+          if (values.get(j).STRING_LITERAL() != null) {
+            
valueList.add(parseStringLiteralInInsertValue(values.get(j).getText()));
           } else {
-            valueList.add(constant.getText());
+            valueList.add(values.get(j).getText());
           }
         }
       }
+
       valuesList.add(valueList.toArray(new String[0]));
     }
     insertStatement.setTimes(timeArray);
     insertStatement.setValuesList(valuesList);
   }
 
+  private long parseTimeValue(ConstantContext constant) {
+    if (constant.INTEGER_LITERAL() != null) {
+      try {
+        if (constant.MINUS() != null) {
+          return -Long.parseLong(constant.INTEGER_LITERAL().getText());
+        }
+        return Long.parseLong(constant.INTEGER_LITERAL().getText());
+      } catch (NumberFormatException e) {
+        throw new SemanticException(
+            String.format("Can not parse %s to long value", 
constant.INTEGER_LITERAL().getText()));
+      }
+    } else if (constant.dateExpression() != null) {
+      return parseDateExpression(constant.dateExpression(), 
CommonDateTimeUtils.currentTime());
+    } else {
+      throw new SemanticException(String.format("Can not parse %s to time", 
constant));
+    }
+  }
+
   // Load File
 
   @Override

Reply via email to