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

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


The following commit(s) were added to refs/heads/rel/1.2 by this push:
     new 7534feb9f0b [To rel/1.2] Feature add insertRecords method to rest 
service (#10838)
7534feb9f0b is described below

commit 7534feb9f0b215ce25d01b3efdde3d53ea19fdd5
Author: CloudWise-Lukemiao 
<[email protected]>
AuthorDate: Tue Aug 29 14:53:44 2023 +0800

    [To rel/1.2] Feature add insertRecords method to rest service (#10838)
    
    Co-authored-by: Cloudwise_Luke <[email protected]>
---
 .../db/protocol/rest/utils/InsertRowDataUtils.java | 105 +++++++++++++++++++++
 .../rest/v1/handler/RequestValidationHandler.java  |  12 +++
 .../v1/handler/StatementConstructionHandler.java   |  60 +++++++++++-
 .../protocol/rest/v1/impl/RestApiServiceImpl.java  |  47 +++++++++
 .../rest/v2/handler/RequestValidationHandler.java  |  12 +++
 .../v2/handler/StatementConstructionHandler.java   |  61 +++++++++++-
 .../protocol/rest/v2/impl/RestApiServiceImpl.java  |  47 +++++++++
 .../openapi/src/main/openapi3/iotdb_rest_v1.yaml   |  52 ++++++++++
 .../openapi/src/main/openapi3/iotdb_rest_v2.yaml   |  52 ++++++++++
 9 files changed, 444 insertions(+), 4 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/utils/InsertRowDataUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/utils/InsertRowDataUtils.java
new file mode 100644
index 00000000000..ba54c77c8dd
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/utils/InsertRowDataUtils.java
@@ -0,0 +1,105 @@
+/*
+ * 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.protocol.rest.utils;
+
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.NoValidValueException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import static org.apache.iotdb.session.Session.MSG_UNSUPPORTED_DATA_TYPE;
+
+public class InsertRowDataUtils {
+
+  private static final String ALL_INSERT_DATA_IS_NULL = "All inserted data is 
null.";
+
+  public static void filterNullValueAndMeasurement(
+      List<String> deviceIds,
+      List<Long> times,
+      List<List<String>> measurementsList,
+      List<List<Object>> valuesList,
+      List<List<TSDataType>> typesList) {
+    for (int i = valuesList.size() - 1; i >= 0; i--) {
+      List<Object> values = valuesList.get(i);
+      List<String> measurements = measurementsList.get(i);
+      List<TSDataType> types = typesList.get(i);
+      boolean isAllValuesNull = getValuesIsEmpty(measurements, types, values);
+      if (isAllValuesNull) {
+        valuesList.remove(i);
+        measurementsList.remove(i);
+        deviceIds.remove(i);
+        times.remove(i);
+        typesList.remove(i);
+      }
+    }
+    if (valuesList.isEmpty()) {
+      throw new NoValidValueException(ALL_INSERT_DATA_IS_NULL);
+    }
+  }
+
+  private static boolean getValuesIsEmpty(
+      List<String> measurementsList, List<TSDataType> types, List<Object> 
valuesList) {
+    for (int i = valuesList.size() - 1; i >= 0; i--) {
+      if (valuesList.get(i) == null) {
+        valuesList.remove(i);
+        measurementsList.remove(i);
+        types.remove(i);
+      }
+    }
+    return valuesList.isEmpty();
+  }
+
+  public static List<Object> reGenValues(List<TSDataType> types, List<Object> 
values)
+      throws IoTDBConnectionException {
+    for (int i = 0; i < values.size(); i++) {
+      if (values.get(i) == null) {
+        continue;
+      }
+      Object val = values.get(i);
+      switch (types.get(i)) {
+        case BOOLEAN:
+        case INT32:
+          break;
+        case INT64:
+          if (val instanceof Number) {
+            values.set(i, ((Number) val).longValue());
+          }
+          break;
+        case FLOAT:
+          if (val instanceof Number) {
+            values.set(i, ((Number) val).floatValue());
+          }
+          break;
+        case DOUBLE:
+          if (val instanceof Number) {
+            values.set(i, ((Number) val).doubleValue());
+          }
+          break;
+        case TEXT:
+          values.set(i, new 
Binary(val.toString().getBytes(StandardCharsets.UTF_8)));
+          break;
+        default:
+          throw new IoTDBConnectionException(MSG_UNSUPPORTED_DATA_TYPE + 
types.get(i));
+      }
+    }
+    return values;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/RequestValidationHandler.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/RequestValidationHandler.java
index 32e97d36fec..dc9dafbf0e3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/RequestValidationHandler.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/RequestValidationHandler.java
@@ -18,6 +18,7 @@
 package org.apache.iotdb.db.protocol.rest.v1.handler;
 
 import org.apache.iotdb.db.protocol.rest.v1.model.ExpressionRequest;
+import org.apache.iotdb.db.protocol.rest.v1.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v1.model.InsertTabletRequest;
 import org.apache.iotdb.db.protocol.rest.v1.model.SQL;
 
@@ -44,6 +45,17 @@ public class RequestValidationHandler {
     Objects.requireNonNull(insertTabletRequest.getValues(), "values should not 
be null");
   }
 
+  public static void validateInsertRecordsRequest(InsertRecordsRequest 
insertRecordsRequest) {
+    Objects.requireNonNull(insertRecordsRequest.getTimestamps(), "timestamps 
should not be null");
+    Objects.requireNonNull(insertRecordsRequest.getIsAligned(), "isAligned 
should not be null");
+    Objects.requireNonNull(insertRecordsRequest.getDeviceIds(), "deviceIds 
should not be null");
+    Objects.requireNonNull(
+        insertRecordsRequest.getDataTypesList(), "dataTypesList should not be 
null");
+    Objects.requireNonNull(insertRecordsRequest.getValuesList(), "valuesList 
should not be null");
+    Objects.requireNonNull(
+        insertRecordsRequest.getMeasurementsList(), "measurementsList should 
not be null");
+  }
+
   public static void validateExpressionRequest(ExpressionRequest 
expressionRequest) {
     Objects.requireNonNull(expressionRequest.getExpression(), "expression 
should not be null");
     Objects.requireNonNull(expressionRequest.getPrefixPath(), "prefixPath 
should not be null");
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/StatementConstructionHandler.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/StatementConstructionHandler.java
index 420132c8442..8b570ba2297 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/StatementConstructionHandler.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/StatementConstructionHandler.java
@@ -19,14 +19,20 @@ package org.apache.iotdb.db.protocol.rest.v1.handler;
 
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.db.exception.WriteProcessRejectException;
+import org.apache.iotdb.db.protocol.rest.utils.InsertRowDataUtils;
+import org.apache.iotdb.db.protocol.rest.v1.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v1.model.InsertTabletRequest;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeDevicePathCache;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.utils.Binary;
 import org.apache.iotdb.tsfile.utils.BitMap;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -115,7 +121,7 @@ public class StatementConstructionHandler {
             if (data == null) {
               bitMaps[columnIndex].mark(rowIndex);
             } else {
-              floatValues[rowIndex] = Float.valueOf(String.valueOf(data));
+              floatValues[rowIndex] = Float.parseFloat(String.valueOf(data));
             }
           }
           columns[columnIndex] = floatValues;
@@ -127,7 +133,7 @@ public class StatementConstructionHandler {
               bitMaps[columnIndex].mark(rowIndex);
             } else {
               doubleValues[rowIndex] =
-                  
Double.valueOf(String.valueOf(rawData.get(columnIndex).get(rowIndex)));
+                  
Double.parseDouble(String.valueOf(rawData.get(columnIndex).get(rowIndex)));
             }
           }
           columns[columnIndex] = doubleValues;
@@ -164,4 +170,54 @@ public class StatementConstructionHandler {
     insertStatement.setAligned(insertTabletRequest.getIsAligned());
     return insertStatement;
   }
+
+  public static InsertRowsStatement createInsertRowsStatement(
+      InsertRecordsRequest insertRecordsRequest)
+      throws IllegalPathException, IoTDBConnectionException {
+
+    // construct insert statement
+    InsertRowsStatement insertStatement = new InsertRowsStatement();
+    List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
+    List<List<TSDataType>> dataTypesList = new ArrayList<>();
+
+    for (int i = 0; i < insertRecordsRequest.getDataTypesList().size(); i++) {
+      List<TSDataType> dataTypes = new ArrayList<>();
+      for (int c = 0; c < 
insertRecordsRequest.getDataTypesList().get(i).size(); c++) {
+        dataTypes.add(
+            TSDataType.valueOf(
+                
insertRecordsRequest.getDataTypesList().get(i).get(c).toUpperCase(Locale.ROOT)));
+      }
+      dataTypesList.add(dataTypes);
+    }
+
+    InsertRowDataUtils.filterNullValueAndMeasurement(
+        insertRecordsRequest.getDeviceIds(),
+        insertRecordsRequest.getTimestamps(),
+        insertRecordsRequest.getMeasurementsList(),
+        insertRecordsRequest.getValuesList(),
+        dataTypesList);
+
+    for (int i = 0; i < insertRecordsRequest.getDeviceIds().size(); i++) {
+      InsertRowStatement statement = new InsertRowStatement();
+      statement.setDevicePath(
+          DataNodeDevicePathCache.getInstance()
+              .getPartialPath(insertRecordsRequest.getDeviceIds().get(i)));
+      statement.setMeasurements(
+          insertRecordsRequest.getMeasurementsList().get(i).toArray(new 
String[0]));
+      statement.setTime(insertRecordsRequest.getTimestamps().get(i));
+      statement.setDataTypes(dataTypesList.get(i).toArray(new TSDataType[0]));
+      List<Object> values =
+          InsertRowDataUtils.reGenValues(
+              dataTypesList.get(i), 
insertRecordsRequest.getValuesList().get(i));
+      statement.setValues(values.toArray());
+      statement.setAligned(insertRecordsRequest.getIsAligned());
+      if (statement.isEmpty()) {
+        continue;
+      }
+      insertRowStatementList.add(statement);
+    }
+    insertStatement.setInsertRowStatementList(insertRowStatementList);
+
+    return insertStatement;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/impl/RestApiServiceImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/impl/RestApiServiceImpl.java
index ab6096179b5..b2c5296515e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/impl/RestApiServiceImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/impl/RestApiServiceImpl.java
@@ -29,6 +29,7 @@ import 
org.apache.iotdb.db.protocol.rest.v1.handler.QueryDataSetHandler;
 import org.apache.iotdb.db.protocol.rest.v1.handler.RequestValidationHandler;
 import 
org.apache.iotdb.db.protocol.rest.v1.handler.StatementConstructionHandler;
 import org.apache.iotdb.db.protocol.rest.v1.model.ExecutionStatus;
+import org.apache.iotdb.db.protocol.rest.v1.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v1.model.InsertTabletRequest;
 import org.apache.iotdb.db.protocol.rest.v1.model.SQL;
 import org.apache.iotdb.db.protocol.session.SessionManager;
@@ -41,6 +42,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult;
 import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution;
 import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
 import org.apache.iotdb.db.queryengine.plan.statement.Statement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
 import org.apache.iotdb.db.utils.SetThreadName;
 import org.apache.iotdb.rpc.TSStatusCode;
@@ -185,6 +187,51 @@ public class RestApiServiceImpl extends RestApiService {
     }
   }
 
+  @Override
+  public Response insertRecords(
+      InsertRecordsRequest insertRecordsRequest, SecurityContext 
securityContext) {
+    Long queryId = null;
+    try {
+      
RequestValidationHandler.validateInsertRecordsRequest(insertRecordsRequest);
+
+      InsertRowsStatement insertRowsStatement =
+          
StatementConstructionHandler.createInsertRowsStatement(insertRecordsRequest);
+
+      Response response = authorizationHandler.checkAuthority(securityContext, 
insertRowsStatement);
+      if (response != null) {
+        return response;
+      }
+      queryId = SESSION_MANAGER.requestQueryId();
+      ExecutionResult result =
+          COORDINATOR.execute(
+              insertRowsStatement,
+              SESSION_MANAGER.requestQueryId(),
+              null,
+              "",
+              partitionFetcher,
+              schemaFetcher,
+              config.getQueryTimeoutThreshold());
+
+      return Response.ok()
+          .entity(
+              (result.status.code == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()
+                      || result.status.code == 
TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode())
+                  ? new ExecutionStatus()
+                      .code(TSStatusCode.SUCCESS_STATUS.getStatusCode())
+                      .message(TSStatusCode.SUCCESS_STATUS.name())
+                  : new ExecutionStatus()
+                      .code(result.status.getCode())
+                      .message(result.status.getMessage()))
+          .build();
+    } catch (Exception e) {
+      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+    } finally {
+      if (queryId != null) {
+        COORDINATOR.cleanupQueryExecution(queryId);
+      }
+    }
+  }
+
   @Override
   public Response insertTablet(
       InsertTabletRequest insertTabletRequest, SecurityContext 
securityContext) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
index 2b7f568edea..b7f71f7be6d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
@@ -18,6 +18,7 @@
 package org.apache.iotdb.db.protocol.rest.v2.handler;
 
 import org.apache.iotdb.db.protocol.rest.v2.model.ExpressionRequest;
+import org.apache.iotdb.db.protocol.rest.v2.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v2.model.InsertTabletRequest;
 import org.apache.iotdb.db.protocol.rest.v2.model.SQL;
 
@@ -44,6 +45,17 @@ public class RequestValidationHandler {
     Objects.requireNonNull(insertTabletRequest.getValues(), "values should not 
be null");
   }
 
+  public static void validateInsertRecordsRequest(InsertRecordsRequest 
insertRecordsRequest) {
+    Objects.requireNonNull(insertRecordsRequest.getTimestamps(), "timestamps 
should not be null");
+    Objects.requireNonNull(insertRecordsRequest.getIsAligned(), "is_aligned 
should not be null");
+    Objects.requireNonNull(insertRecordsRequest.getDevices(), "devices should 
not be null");
+    Objects.requireNonNull(
+        insertRecordsRequest.getDataTypesList(), "data_types_list should not 
be null");
+    Objects.requireNonNull(insertRecordsRequest.getValuesList(), "values_list 
should not be null");
+    Objects.requireNonNull(
+        insertRecordsRequest.getMeasurementsList(), "measurements_list should 
not be null");
+  }
+
   public static void validateExpressionRequest(ExpressionRequest 
expressionRequest) {
     Objects.requireNonNull(expressionRequest.getExpression(), "expression 
should not be null");
     Objects.requireNonNull(expressionRequest.getPrefixPath(), "prefix_path 
should not be null");
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/StatementConstructionHandler.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/StatementConstructionHandler.java
index 8ef8401b3cb..794daff8372 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/StatementConstructionHandler.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/StatementConstructionHandler.java
@@ -19,14 +19,20 @@ package org.apache.iotdb.db.protocol.rest.v2.handler;
 
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.db.exception.WriteProcessRejectException;
+import org.apache.iotdb.db.protocol.rest.utils.InsertRowDataUtils;
+import org.apache.iotdb.db.protocol.rest.v2.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v2.model.InsertTabletRequest;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeDevicePathCache;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.utils.Binary;
 import org.apache.iotdb.tsfile.utils.BitMap;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -115,7 +121,7 @@ public class StatementConstructionHandler {
             if (data == null) {
               bitMaps[columnIndex].mark(rowIndex);
             } else {
-              floatValues[rowIndex] = Float.valueOf(String.valueOf(data));
+              floatValues[rowIndex] = Float.parseFloat(String.valueOf(data));
             }
           }
           columns[columnIndex] = floatValues;
@@ -127,7 +133,7 @@ public class StatementConstructionHandler {
               bitMaps[columnIndex].mark(rowIndex);
             } else {
               doubleValues[rowIndex] =
-                  
Double.valueOf(String.valueOf(rawData.get(columnIndex).get(rowIndex)));
+                  
Double.parseDouble(String.valueOf(rawData.get(columnIndex).get(rowIndex)));
             }
           }
           columns[columnIndex] = doubleValues;
@@ -164,4 +170,55 @@ public class StatementConstructionHandler {
     insertStatement.setAligned(insertTabletRequest.getIsAligned());
     return insertStatement;
   }
+
+  public static InsertRowsStatement createInsertRowsStatement(
+      InsertRecordsRequest insertRecordsRequest)
+      throws IllegalPathException, IoTDBConnectionException {
+
+    // construct insert statement
+    InsertRowsStatement insertStatement = new InsertRowsStatement();
+    List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
+    List<List<TSDataType>> dataTypesList = new ArrayList<>();
+
+    for (int i = 0; i < insertRecordsRequest.getDataTypesList().size(); i++) {
+      List<TSDataType> dataTypes = new ArrayList<>();
+      for (int c = 0; c < 
insertRecordsRequest.getDataTypesList().get(i).size(); c++) {
+        dataTypes.add(
+            TSDataType.valueOf(
+                
insertRecordsRequest.getDataTypesList().get(i).get(c).toUpperCase(Locale.ROOT)));
+      }
+      dataTypesList.add(dataTypes);
+    }
+
+    InsertRowDataUtils.filterNullValueAndMeasurement(
+        insertRecordsRequest.getDevices(),
+        insertRecordsRequest.getTimestamps(),
+        insertRecordsRequest.getMeasurementsList(),
+        insertRecordsRequest.getValuesList(),
+        dataTypesList);
+
+    for (int i = 0; i < insertRecordsRequest.getDevices().size(); i++) {
+      InsertRowStatement statement = new InsertRowStatement();
+      statement.setDevicePath(
+          DataNodeDevicePathCache.getInstance()
+              .getPartialPath(insertRecordsRequest.getDevices().get(i)));
+      statement.setMeasurements(
+          insertRecordsRequest.getMeasurementsList().get(i).toArray(new 
String[0]));
+      statement.setTime(insertRecordsRequest.getTimestamps().get(i));
+      statement.setDataTypes(dataTypesList.get(i).toArray(new TSDataType[0]));
+      List<Object> values =
+          InsertRowDataUtils.reGenValues(
+              dataTypesList.get(i), 
insertRecordsRequest.getValuesList().get(i));
+      statement.setValues(values.toArray());
+      statement.setAligned(insertRecordsRequest.getIsAligned());
+      // skip empty statement
+      if (statement.isEmpty()) {
+        continue;
+      }
+      insertRowStatementList.add(statement);
+    }
+    insertStatement.setInsertRowStatementList(insertRowStatementList);
+
+    return insertStatement;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
index f1e03ba86bc..c2fc177ba31 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
@@ -29,6 +29,7 @@ import 
org.apache.iotdb.db.protocol.rest.v2.handler.QueryDataSetHandler;
 import org.apache.iotdb.db.protocol.rest.v2.handler.RequestValidationHandler;
 import 
org.apache.iotdb.db.protocol.rest.v2.handler.StatementConstructionHandler;
 import org.apache.iotdb.db.protocol.rest.v2.model.ExecutionStatus;
+import org.apache.iotdb.db.protocol.rest.v2.model.InsertRecordsRequest;
 import org.apache.iotdb.db.protocol.rest.v2.model.InsertTabletRequest;
 import org.apache.iotdb.db.protocol.rest.v2.model.SQL;
 import org.apache.iotdb.db.protocol.session.SessionManager;
@@ -41,6 +42,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult;
 import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution;
 import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
 import org.apache.iotdb.db.queryengine.plan.statement.Statement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
 import org.apache.iotdb.db.utils.SetThreadName;
 import org.apache.iotdb.rpc.TSStatusCode;
@@ -185,6 +187,51 @@ public class RestApiServiceImpl extends RestApiService {
     }
   }
 
+  @Override
+  public Response insertRecords(
+      InsertRecordsRequest insertRecordsRequest, SecurityContext 
securityContext) {
+    Long queryId = null;
+    try {
+      
RequestValidationHandler.validateInsertRecordsRequest(insertRecordsRequest);
+
+      InsertRowsStatement insertRowsStatement =
+          
StatementConstructionHandler.createInsertRowsStatement(insertRecordsRequest);
+
+      Response response = authorizationHandler.checkAuthority(securityContext, 
insertRowsStatement);
+      if (response != null) {
+        return response;
+      }
+      queryId = SESSION_MANAGER.requestQueryId();
+      ExecutionResult result =
+          COORDINATOR.execute(
+              insertRowsStatement,
+              SESSION_MANAGER.requestQueryId(),
+              null,
+              "",
+              partitionFetcher,
+              schemaFetcher,
+              config.getQueryTimeoutThreshold());
+
+      return Response.ok()
+          .entity(
+              (result.status.code == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()
+                      || result.status.code == 
TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode())
+                  ? new ExecutionStatus()
+                      .code(TSStatusCode.SUCCESS_STATUS.getStatusCode())
+                      .message(TSStatusCode.SUCCESS_STATUS.name())
+                  : new ExecutionStatus()
+                      .code(result.status.getCode())
+                      .message(result.status.getMessage()))
+          .build();
+    } catch (Exception e) {
+      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+    } finally {
+      if (queryId != null) {
+        COORDINATOR.cleanupQueryExecution(queryId);
+      }
+    }
+  }
+
   @Override
   public Response insertTablet(
       InsertTabletRequest insertTabletRequest, SecurityContext 
securityContext) {
diff --git a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v1.yaml 
b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v1.yaml
index 18080c693ab..f2e439d4400 100644
--- a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v1.yaml
+++ b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v1.yaml
@@ -49,6 +49,24 @@ paths:
               schema:
                 $ref: '#/components/schemas/ExecutionStatus'
 
+  /rest/v1/insertRecords:
+    post:
+      summary: insertRecords
+      description: insertRecords
+      operationId: insertRecords
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/InsertRecordsRequest'
+      responses:
+        "200":
+          description: ExecutionStatus
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ExecutionStatus'
+
   /rest/v1/nonQuery:
     post:
       summary: executeNonQueryStatement
@@ -195,6 +213,40 @@ components:
         deviceId:
           type: string
 
+    InsertRecordsRequest:
+      title: InsertRecordsRequest
+      type: object
+      properties:
+        timestamps:
+          type: array
+          items:
+            type: integer
+            format: int64
+        measurementsList:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        dataTypesList:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        valuesList:
+          type: array
+          items:
+            type: array
+            items:
+              type: object
+        isAligned:
+          type: boolean
+        deviceIds:
+          type: array
+          items:
+            type: string
+
     ExecutionStatus:
       type: object
       properties:
diff --git a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml 
b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
index 4dfdb14cb91..68dac502d94 100644
--- a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
+++ b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
@@ -49,6 +49,24 @@ paths:
               schema:
                 $ref: '#/components/schemas/ExecutionStatus'
 
+  /rest/v2/insertRecords:
+    post:
+      summary: insertRecords
+      description: insertRecords
+      operationId: insertRecords
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/InsertRecordsRequest'
+      responses:
+        "200":
+          description: ExecutionStatus
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ExecutionStatus'
+
   /rest/v2/nonQuery:
     post:
       summary: executeNonQueryStatement
@@ -195,6 +213,40 @@ components:
         device:
           type: string
 
+    InsertRecordsRequest:
+      title: InsertRecordsRequest
+      type: object
+      properties:
+        timestamps:
+          type: array
+          items:
+            type: integer
+            format: int64
+        measurements_list:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        data_types_list:
+          type: array
+          items:
+            type: array
+            items:
+              type: string
+        values_list:
+          type: array
+          items:
+            type: array
+            items:
+              type: object
+        is_aligned:
+          type: boolean
+        devices:
+          type: array
+          items:
+            type: string
+
     ExecutionStatus:
       type: object
       properties:

Reply via email to