private void parseInsertValuesSpec(
      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<Object[]> valuesList = new ArrayList<>();
    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<Object> valueList = new ArrayList<>();
      // using now() instead
      if (timeIndex == -1) {
        timestamp = CommonDateTimeUtils.currentTime();
      } else {
        timestamp = parseTimeValue(row.constant(timeIndex));
        TimestampPrecisionUtils.checkTimestampPrecision(timestamp);
      }
      timeArray[i] = timestamp;

      // parse values
      List<ConstantContext> values = row.constant();
      for (int j = 0, columnCount = values.size(); j < columnCount; j++) {
        if (j != timeIndex) {
          if (values.get(j).dateExpression() != null) {
            valueList.add(
                parseDateExpression(
                    values.get(j).dateExpression(), CommonDateTimeUtils.currentTime()));
          } else if (values.get(j).STRING_LITERAL() != null) {
            valueList.add(parseStringLiteralInInsertValue(values.get(j).getText()));
          } else {
            valueList.add(values.get(j).getText());
          }
        }
      }

      valuesList.add(valueList.toArray(new Object[0]));
    }
    insertStatement.setTimes(timeArray);
    insertStatement.setValuesList(valuesList);
  }
Parse time range (startTime and endTime) in group by time.

@throws SemanticException if startTime is larger or equals to endTime in timeRange
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java